I am having trouble putting together some code in which I wish to have the following:
Have a header file myHeader.h in which I create a type struct myStruct with members int number1, int number2 and int number3. This file would also contain a "getter" prototype for getting the address of each of the members in a struct instance.
A translation unit (file.c) in which I declare a static instance of struct myStruct, i.e. static struct myStruct myStructInstance. This translation unit defines the "getter" functions (I will illustrate with a code example at the end of the post).
Another header file anotherHeader.h in which I wish to - now this is a tricky bit that's causing problems for me - get the addresses of each of the members of a static structure and use them for something.
Here's an example to show what I am talking about.
myHeader.h
struct myStruct{
int number1;
int number2;
int number3;
};
int* get_number1(void);
int* get_number2(void);
int* get_number3(void);
file.c
#include <myHeader.h>
static struct myStruct myStructInstance = {
.number1 = 0,
.number2 = 0,
.number3 = 0
};
int* get_number1(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number1Address = &(ptr_myStructInstance->number1);
return number1Address;
}
int* get_number2(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number2Address = &(ptr_pfcVariables->number2);
return number2Address;
}
int* get_number3(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number3Address = &(ptr_myStructInstance->number3);
return number3Address;
}
anotherHeader.h
#include <myHeader.h>
int* pNumber1 = get_number1();
int* pNumber2 = get_number2();
int* pNumber3 = get_number3();
The problem is that the code shown above throws "initializer element is not constant" error in anotherHeader.h. I've read a few answers as to why we cannot use non-constant expressions when initializing variables with static storage duration, however I do not understand how this relates to my code.
I've read a few answers as to why we cannot use non-constant expressions when initializing variables with static storage duration, however I do not understand how this relates to my code.
A function call is a non-constant expression.
int* pNumber1 = get_number1();
The above code is trying to initialize a global variable with a non-constant expression.
You simply can't call code in the global scope.
However, you could easily accomplish the same thing as what you appear to be trying to do by simply extending myHeader.h with:
extern int *pNumber1, *pNumber2, *pNumber3;
and then allocating and initializing these in file.c with:
int *pNumber1 = &myStructInstance.number1,
*pNumber2 = &myStructInstance.number2,
*pNumber3 = &myStructInstance.number3;
Related
I am trying to understand why the following code compiles and runs fine. I would expect any assignment using data inside f not to compile with a gcc error assignment of member ‘i’ in read-only object. Is there some kind of exception, because data.i is allocated dynamically?
#include <stdio.h>
#include <stdlib.h>
struct a {
int *i;
};
void f(const struct a *data) {
data->i[0] = 55;
}
int main() {
struct a data;
data.i = malloc(2 * sizeof(int));
f(&data);
printf("%d\n", data.i[0]);
return 0;
}
const front of a struct will make it read-only. If the struct contains pointer members, then those pointers themselves will turn read-only. Not what they point at.
That is, const struct a will make the member i behave is if it was declared as int *const i;, meaning that the pointer itself cannot be changed to point elsewhere. The pointed-at data is still of read/write int though.
If you want to restrict access to i inside a function, you should make that function take a const int* parameter and pass the i member to that function.
In the below code, const indicates what data points to is not to be modified. data->i[0] = 55; does not modify the pointer data->i. Instead that line of code modifies the memory pointed to by data->i. This is allowed as pointer .i is int * and not const int *.
struct a {
int *i;
};
void f(const struct a *data) {
data->i[0] = 55;
}
You cant modify i but you can modify the objects referenced by i.
To prevent it you need to:
struct a {
const int *i;
};
Context
We have three files:
module.h: it holds the declaration of a structure,
module.c: it holds the definition of the structure,
main.c: it holds an instance of the structure.
The goal is to use a structure in main.c by using an API (module.h) and not directly by manipulating the structure members. It is why the definition of the structure is in module.c and not in module.h.
Code
module.h
#ifndef MODULE_H
#define MODULE_H
typedef struct test_struct test_struct;
void initialize_test_struct(int a, int b, test_struct * test_struct_handler);
#endif
module.c
#include "module.h"
struct test_struct
{
int a;
int b;
};
void initialize_test_struct(int a, int b, test_struct * test_struct_handler)
{
test_struct_handler->a = a;
test_struct_handler->b = b;
}
main.c
#include "module.h"
int main(void)
{
test_struct my_struct; // <- GCC error here
test_struct * my_struct_handler = &my_struct;
initialize_test_struct(1, 2, my_struct_handler);
return 0;
}
Problem
If we compile those files with GCC, we will get the following error:
main.c:7:17: error: storage size of ‘my_struct’ isn’t known
Question
How can we force to use an API and so forbid to use directly a structure's members to manipulate a structure, the structure declaration and definition being in a different module than the main.c?
Since the definition of test_struct is not visible to your main function, you cannot create an instance of this object nor can you access its members. You can however create a pointer to it. So you need a function in module.c that allocates memory for an instance and returns a pointer to it. You'll also need functions to read the members.
In module.h:
test_struct *allocate_test_struct();
int get_a(test_struct *p);
int get_b(test_struct *p);
In module.c:
test_struct *allocate_test_struct()
{
test_struct *p = malloc(sizeof(test_struct));
if (!p) {
perror("malloc failed");
exit(1);
}
return p;
}
int get_a(test_struct *p)
{
return p->a;
}
int get_b(test_struct *p)
{
return p-b;
}
In main.c:
test_struct * my_struct_handler = allocate_test_struct()
initialize_test_struct(1, 2, my_struct_handler);
printf("%d\n", get_a(my_struct_handler));
printf("%d\n", get_b(my_struct_handler));
free(my_struct_handler);
You cannot instantiate a test_struct directly with only the include file because the details are not known when the C file is processed in the compiler. The language will only let you initialize pointers to objects of unknown size, not the objects themselves. The size and other details of test_struct are only known by the compiler when processing module.c
To get around this, you need to have module.c allocate data and provide a pointer to it in the initialize call. This means you have to either have the initialize function return a pointer to a newly created object (one that was either malloc'd or a global or static object), or have the function accept a test_struct **:
void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)
{
*test_struct_handler = malloc(sizeof(test_struct));
//Do rest of init. You should also check return value of malloc
}
//Alternatively
test_struct * initialize_test_struct(int a, int b)
{
test_struct *temp;
temp = malloc(sizeof(test_struct);
//Init members as needed
return temp;
}
Normally in this situation the typedef is for a pointer to the opaque structure, and named to indicate that it's not the struct itself - 'typedef struct test_struct* test_struct_handle' could be appropriate, as the struct name itself is rather useless to users of the module (except to make pointers).
It's also good practice to:
Have accessor functions if you need them (which you do for your main file - see dbush's answer)
Have a 'de-init'/'free' function. The user does not necessarily know that malloc was used, and having a de-init function will make it possible to hide more implementation details.
First, what is it that you think clients of your library want to do that your API doesn’t support, and they’ll be tempted to manipulate the fields of your structure to accomplish? Consider extending the API.
One option is to force client code to get its structures from your factory function, rather than allocate them itself.
Another is to create a phony definition, perhaps containing only an array of char to establish a minimum size and alignment, so that the client code knows just enough to allocate an array of them, and the library module itself can cast the pointer and twiddle the bits.
Another is to put the definition in the header and add a comment saying that the fields are internal implementation details that might change.
Another is to port to an object-oriented language.
If we compile those files with GCC, we will get the following error:
main.c:7:17: error: storage size of ‘my_struct’ isn’t known
The reason why structures are inside the header files in the first place is so that the user source (here main.c) can access its members...
Your compiler does not know the address of the definition-less struct typedef struct test_struct test_struct; and so &my_struct won't give you its address!
And without an address, you can not get the size of any variable!
Explanation:
test_struct my_struct;
Here, you make a variable of an incomplete type and hence is not valid and doesn't have an address since its members are inaccessible...
test_struct * my_struct_handler = &my_struct;
And here you pass the address of my_struct which unnotably is not possible to gain (The structure is definition-less inside the header and the source is compiled so it can't be accessed either)...
So you use pointers in this case so that a temporary address can be assigned to the incomplete type:
/* Don't forget to change to
* 'void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)'
* in the header file!
*/
void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)
{
// Allocate an undefined address to the pointer...
*test_struct_handler = malloc(sizeof(test_struct));
(*test_struct_handler)->a = a;
(*test_struct_handler)->b = b;
}
// The declarations have to be present inside the headers as well...
// A function that returns the pointer to the variables a and b respectively...
// These functions can readily change their values while returning them...
int * get_a_ref(test_struct * test_struct_handler)
{
return &test_struct_handler->a;
}
int * get_b_ref(test_struct * test_struct_handler)
{
return &test_struct_handler->b;
}
and use it in main like this:
#include <stdio.h>
#include "module.h"
int main(void)
{
test_struct * my_struct_handler;
// Here a address is malloc'd to the pointer and the value is assigned to it...
initialize_test_struct(1, 2, &my_struct_handler);
// Will change the value of 'a' and similar for b as well...
// *get_a_ref(my_struct_handler) = 10;
printf("%d\n", *get_a_ref(my_struct_handler));
printf("%d\n", *get_b_ref(my_struct_handler));
return 0;
}
Just to remind you about the magic (and obscurity) of typedefs...
I'm writing code in C that initializes a bunch of structures using parts of other structures. For example:
//Original structure
struct
{
int foo1;
int foo2;
int foo3;
} orig_struct = {1,2,3};
//New structure
struct
{
int bar1;
int bar2;
} new_struct = {orig_struct.foo1, orig_struct.foo2};
I have to do this for a lot of structures, and the initialization method above makes the code look very clean and readable. To be clear, I don't have any control over the original structures. I'm just creating the new structures to capture data from them.
I ran into an issue when one of the structures had a large array:
//Original structure
struct
{
int foo1;
int foo2[50];
int foo3;
} orig_struct = {1,{2,3,etc},52}; //<--replace "etc" with 48 more int values
//New structure
struct
{
int bar1;
int bar2[50];
} new_struct = {orig_struct.foo1, XXX};
Is there anything I can replace XXX with to initialize the array in the new structure with the values in the array of the original structure? Again, I'd like to keep a clean, consistent look to my code, so keeping it within the curly brackets would be ideal. I know I can manually type out each element of the array within their own curly brackets:
...
} new_struct = {orig_struct.foo1, {orig_struct.foo2[0],orig_struct.foo2[1],orig_struct.foo2[2],orig_struct.foo2[3],etc}
But it's pretty obvious why that can quickly become untenable.
Note that your syntax for initializing new_struct does not work if new_struct has static storage duration, since a constant expression is required in that case.
There really isn't any way to directly assign an array to another array. This is only allowed if the array itself is encapsulated by a structure, and you are using structure assignment. Since your original structure and new structure share a common initial prefix, you could try to exploit this through a union:
struct orig_struct_type orig_struct = {1,{2,3},52};
void some_function ()
{
union {
struct orig_struct_type o;
struct new_struct_type n;
} *u = (void *)&orig_struct;
struct new_struct_type new_struct = u->n;
/* ... */
}
If you are simply trying to reduce code duplication, you can place the array initializer list into a macro.
#define VALUES {2,3,etc} //<--replace "etc" with 48 more int
//Original structure
struct
{
int foo1;
int foo2[50];
int foo3;
} orig_struct = {1,VALUES,52};
void some_function ()
{
struct
{
int bar1;
int bar2[50];
} new_struct = {orig_struct.foo1, VALUES};
/* ... */
}
In c, I see no way to do this within an initializer, as assigning an array is not supported, and expressions must be constant expressions; so a loop or memcpy is not possible during initialization (cf. array initialization reference):
As with all other initialization, every expression in the initializer
list must be a constant expression when initializing arrays of static
or thread-local storage duration:
Later on, of course, you could write memcpy(new_struct.bar2, orig_struct.foo2, sizeof(new_struct.bar2)), but this code is then separated from the struct/variable declaration.
My aim is to initialize a local static int variable.
I want to initialize my variable with the value that equals to offset value of a struct member.
My struct definition
struct member{
int ID;
char *NAME;
int NO;
};
Global Struct declaration
struct member FirstMember={.ID = 123, .NAME ="John", .NO=7382737};
struct member SecondMember={.ID = 120, .NAME ="Bill", .NO=454545};
Function and local static variable declaration
void foo()
{
static int offset = (int)(&FirstMember.NO - &SecondMember.ID );
}
Compiler output: Error[Pe028]: expression must have a constant value..
As far as I know static local variables must be initialized with const values. Compiler also knows the address values of the struct and its members. So compiler is able to calculate the difference between member addresses. But it returns an error message.
But this initialization works
void foo()
{
static int offset = (int)(&FirstMember.NO - &FirstMember.ID );
}
Could you please explain the point that I missed?
I think the problem is in your structure declaration: Name shoul be "char *" not "char" because you try to initialize it with "John" (type const char *).
This is working for me:
struct member{
int ID;
char* NAME;
int NO;
};
struct member FirstMember={123,"John",7382737};
void foo()
{
static int offset = (int)(&FirstMember.NO - &FirstMember.ID );
}
The second problem is that you want to initialize a "static" variable with an unknown value before run time.
All the static variables are in a separate place named "initialized data" section and the compiler needs to know exactly the value of each static variable at compile time because these values are "hardcoded" inside your binary file.
Even for this code:
int a = 10;
static int x = a;
you will have the same problem because "a" is not evaluated at compile time but at run-time.
Here is the case. In the file "fileA.c" I have
typedef struct MY_STRUCT
{
int A;
int B;
int C;
}MY_STRUCT;
MY_STRUCT Data;
/* Function */
int function(MY_STRUCT *params)
{
int varA, varB, varC;
varA = params->A;
varB = params->B;
varC = params->C;
}
And I need to fill the struct elements from other routine, for instance, "fileB.c" which contains the following:
extern MY_STRUCT Data;
int function(MY_STRUCT *params);
/* Function */
void userMain(void)
{
Data.A = 1254;
Data.B = 5426;
Data.C = 1236;
function(&Data);
}
But I'm getting the error:
"[Error] fileB.c E208: syntax error - token ";" inserted before "Data"
And whe I cross probe the error the compiler take me to the declaration "extern MY_STRUCT Data;"
So my question is how do I accomplish this functionality? I mean, how do I fill the elements of the structure from another function in another file different from the file where I declared the struct?
When the compiler is compiling fileB.c, it doesn't know about the typedef that you've defined in fileA.c. So in fileB.c, MY_STRUCT is an unknown type.
You should move the typedef to a common header, and include it in fileA.c and fileB.c.
Elaborating a bit on #pb2q answer:
Create a filea.h file with (omitting the defines and stuff):
struct MY_STRUCT
{
(blah blah blah ...)
};
extern MY_STRUCT Data;
This will declare the struct and tell whoever wants to know that the variable is declared in another file. Then put in filea.c the following lines
#include "filea.h" // near the top
(...)
MY_STRUCT Data; // Somewhere meaningful
This will actually declare the variable Data. Finally, in file "fileb.c" type
#include "filea.h"
that allows you to use the variable Data.