I like to create scenarios in my code where I declare a static global struct inside a .c file that everyone will share, it contains configuration stuff. Right underneath the declaration, I'll create a constant pointer to this struct and put this in the .h file so that everyone can get access to it.
Sometimes, within a .c file, I like to have a global pointer to the specific configuration that that .c file cares about, that way I don't have constantly keep referencing the global struct, because sometimes I'll get this configuration from a different source on different projects.
The issue that I have is that I can't define this "local global" pointer because the initializer element is not constant. Here is an example.
typedef struct
{
int Value;
} mystruct_t, *pmystruct_t;
static const mystruct_t GlobalStruct;
const pmystruct_t pGlobalStruct = &GlobalStruct;
const int *ValuePtr = &pGlobalStruct->Value;
int main()
{
*ValuePtr = 10;
return 0;
}
I tried reading on the const keywords for pointer in C, and I thought I understood it, but apparently it's still a mystery to me. The line of code that I tried, and may gotten me closer to that piece of code to compile is
const mystruct_t const *pGlobalStruct = &GlobalStruct;
However, it still doesn't compile because ValuePtr initializer element is not constant (the error I get).
The end goal here is to have ValuePtr be a constant, where no one can change where it is pointing to, but allow change the elements of the struct that it is pointing to.
EDIT: I want ValuePtr to use pGlobalStruct
The definition
const pmystruct_t pGlobalStruct = &GlobalStruct;
makes the variable (the pointer itself) pGlobalStruct constant, not the structure that it points to.
This is only one of the many flaws that hiding pointers behind type-aliases have.
And to make the definition of ValuePtr valid as well, then you need to make both the pointer variable as well as the structure it points to constant:
const mystruct_t * const pGlobalStruct = &GlobalStruct;
Now pGlobalStruct is a constant pointer to a constant mystruct_t object.
Do not hide pointers behind the typedefs.
If your pointer is referencing constant object you cant assign it with the value. You can only initialize the object.
const int x = 10; //initialization
cosnt int *ptr = &x;
How do I get a const pointer to a const struct?
All possible combinations below:
struct str
{
int x;
float b;
};
struct str a;
const struct str b;
const struct str *c;
struct str * const d;
const struct str * const e;
a - not const structure
b - const structure
c - not const pointer to const structure
d - const pointer to not const structure
e - const pointer to const structure
In your case
const mystruct_t * const pGlobalSttruct = &GlobalStruct;
I have the following struct:
struct foo
{
...
char* cp;
};
And I want to pass a struct foo type pointer to a function, but I want the function to cast the pointer to const char* const cp, and I don't want the const qualifier as part of the definition of struct foo. Declaring the function as:
void func (const struct foo* foo_i);
will ensure the pointer cp is unchanged, but not the data it points to. Is there a way to declare the function so that the data is ensured to be read-only too?
What you describe is not possible.
Consider making cp of type const char*.
I have code as:
typedef struct t
{
uint8 a[100];
}t;
t tt; //object of the struct
f(&tt); //some file calling the func
//function body in some file
uint8 *f(const struct t *ptr)
{
return ptr->a;
}
When I try to build I get the error:
Return value type does not match the function type.
Am I missing something?
You need to use the name of the type, there is no struct t type defined anywhere in your code, so
uint8 *f(t *const tt);
should be the function signature, of course I suppose you are using meaninful names in your real code.
Also, note that I didn't make the pointee const because if you return a non-const pointer to a const pointer to the structure then undefined behavior might happen, the alternative being of course
const uint8 *f(const t *const tt);
The second const, just prevents accidentaly reassigning tt.
If I have created a C module that presents a handle to the user with a pointer to a forward declared struct, like so:
typedef struct FOO_Obj *FOO_Handle;
If I then declare function prototypes that use it as a const qualified parameter thusly:
void FOO_work(const FOO_Handle fooHandle);
How is the const-ness applied?
const struct FOO_Obj *FOO_Handle // A
struct FOO_Obj *const FOO_Handle // B
const struct FOO_Obj *const FOO_Handle // C
Or is it UB?
B. ( There is no undefined behavior with the code you presented. )
The function call
void FOO_work(const FOO_Handle fooHandle);
is equivalent to
void FOO_work(struct FOO_Obj* const fooHandle);
Variable fooHandle in the function will becode a const pointer to a non-const struct FOO_Obj object. You will not be able to add the const qualifier to fooHandle to make it a pointer to a const object.
Instead, if you want to have a pointer to a const object, and keep the struct hidden, you must make another typedef:
typedef const struct FOO_Obj* FOO_ConstHandle;
Can someone tell me the difference between these two versions of a declaration of a structure?
struct S
{
uint8_t a;
};
and
const struct S
{
uint8_t a;
}
Followed by:
void main(void)
{
struct S s = {1};
s.a++;
}
Hint, i've tried both versions for S in Visual Studio C++ 2010 Express so I know that both compile with errors.
Is the "const struct" doing nothing at all? "const struct S s = {1};" certainly does, but that's not the issue at the moment.
Regards
Rich
/********************************************/
I've just worked out what
const struct <typename> <{type}> <variable instances a, b, .., z>;
is doing:
When const is present before the "struct", all variable instances are const, as though they'd be defined with:
const struct <typename> a, b, z;
So it does do something, but not when there's no instance definitions in-line with the struct declaration.
Rich
A declaration of structure just defines the data type.
const qualifier appies to a variable not a data type. So adding const preceeding a struct declaration should be redundant at the most.
With:
const struct S
{
uint8_t a;
};
The const qualifier there is nonsense, and may even cause a compilation error with some C compilers. gcc issues a warning.
The intent appears to be to declare the data type struct S. In this case, the proper syntax is:
struct S
{
uint8_t a;
};
const struct S
{
uint8_t a;
};
is not a valid construct.
This
const struct S
{
uint8_t a;
} x;
could possibly be valid as you're declaring a variable x that is now const, meaning it cannot change.
The const qualifier applies to variables or members.
To instantiate a const variable, just specify const during instantiation.
What const does, is:
during compilation, verify that only reads are performed on the const variables
if the const variable is created with a value which can be resolved during compilation, put the variable in the program memory
When const is applied to members, like in:
struct T {
int const i;
int j;
};
You can only (legally) assign the value i during the creation of the structure.
You may be able to modify a const value (if the program memory sits in RAM and not ROM) by casting it to a non-const type (const-cast) but this is something you shouldn't do.
The typical usage of const-cast is when you use a library which does not specify the constness in function declarations, and your code does. At this point if you want to use it you have to trust it and cast parameters before calling its functions.
It is nonsense to use const keyword before struct.
If you are using gcc compiler, it shows you the following warning:
warning: useless type qualifier in empty declaration [enabled by default]
This is the only use I can think of:
const struct S {
int a;
int b;
} s;
This declares a struct and immediately creates an instance for it named s and at this point, a and b in s are initialized to 0 (please note that at this point s is a global variable in the translation unit which it has been declared in and can be externally linked to).
printf("a = %d\t b = %d\n", s.a, s.b); // a = 0 b = 0
If you try to set members of s, you will fail:
s.a = 1; //error: assignment of member ‘a’ in read-only object
So, s is not really useful here...unless you do something like:
const struct S {
int a;
int b;
} s = { 1, 2 };
Now let's create another instance of the same struct (declaration is still same as above):
struct S other;
other.a = 1;
other.b = 2;
printf("a = %d\t b = %d\n", other.a, other.b); // a = 1 b = 2
The compiler will not complain anymore as other is not const! only s is const!
Now, what that const do, you may ask? let's try to change s:
s = other; // error: assignment of read-only variable ‘s’
That is all to it. If you did not need the compiler to allocate storage for s at the point of declaration and still needed an instance of s to be const you would just add const at the point of instantiating struct S (note the capital S!!)
Bonus 1
const struct S {
int a;
int b;
};
note that there is no small s anymore. At this point, GCC will warn you that const qualifier does not do anything!!!!
Bonus 2
If you want every instance of the struct to be const, that is its members can only be initialized at the point of definition you can do like (using typedef):
typedef const struct S {
int a;
int b;
} s;
// The wrong way
s thisIsAnS;
thisIsAnS.a = 1; //error: assignment of member ‘a’ in read-only object
// The correct way
s thisIsAnS = { 1 , 2 }; //compiles fine, but you can not change a or b anymore
Conclusion
To me, this is just syntactic sugar and only adds unnecessary complexity to the code. But who am I to judge...
When you declare
const var;
then it allocate the some memory space for it but
struct var;
it was just an declaration compiler does not allocate any space for it.
so it shows the error and in const struct you didn't declare any varible see the code so it shows error.