Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize const in a struct in C (with malloc)

I have tried;

void *malloc(unsigned int); struct deneme {     const int a = 15;     const int b = 16; };  int main(int argc, const char *argv[]) {     struct deneme *mydeneme = malloc(sizeof(struct deneme));     return 0; } 

And this is the compiler's error:

gereksiz.c:3:17: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token 

And, also this;

void *malloc(unsigned int); struct deneme {     const int a;     const int b; };  int main(int argc, const char *argv[]) {     struct deneme *mydeneme = malloc(sizeof(struct deneme));     mydeneme->a = 15;     mydeneme->b = 20;     return 0; } 

And this is the compiler's error:

gereksiz.c:10:5: error: assignment of read-only member 'a' gereksiz.c:11:5: error: assignment of read-only member 'b' 

And neither got compiled. Is there any way to initialize a const variable inside a struct when allocation memory with malloc?

like image 826
yasar Avatar asked Mar 13 '12 20:03

yasar


People also ask

Can we use const inside structure?

No, using const in such a way is not a good idea. By declaring your structure fields as const , you are declaring an intention that those fields will never change their value.

How do you initialize a const?

To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.

Can struct members be const?

You can const individual members of a struct. Declaring an entire instance of a struct with a const qualifier is the same as creating a special-purpose copy of the struct with all members specified as const .

Is it necessary to initialize const variables?

In C++ the const keyword has been improved and you can declare real const values. That's why it has to be initialized before compiling the code. The rule is slightly different: to be used in an integral constant expression, the initialization must be visible to the compiler.


2 Answers

You need to cast away the const to initialize the fields of a malloc'ed structure:

struct deneme *mydeneme = malloc(sizeof(struct deneme)); *(int *)&mydeneme->a = 15; *(int *)&mydeneme->b = 20; 

Alternately, you can create an initialized version of the struct and memcpy it:

struct deneme deneme_init = { 15, 20 }; struct deneme *mydeneme = malloc(sizeof(struct deneme)); memcpy(mydeneme, &deneme_init, sizeof(struct deneme)); 

You can make deneme_init static and/or global if you do this a lot (so it only needs to be built once).


Explanation of why this code is not undefined behaviour as suggested by some of the comments, using C11 standard references:

  • This code does not violate 6.7.3/6 because the space returned by malloc is not "an object defined with a const-qualified type". The expression mydeneme->a is not an object, it is an expression. Although it has const-qualified type, it denotes an object which was not defined with a const-qualified type (in fact, not defined with any type at all).

  • The strict aliasing rule is never violated by writing into space allocated by malloc, because the effective type (6.5/6) is updated by each write.

(The strict aliasing rule can be violated by reading from space allocated by malloc however).

In Chris's code samples, the first one sets the effective type of the integer values to int, and the second one sets the effective type to const int, however in both cases going on to read those values through *mydeneme is correct because the strict-aliasing rule (6.5/7 bullet 2) permits reading an object through an expression which is equally or more qualified than the effective type of the object. Since the expression mydeneme->a has type const int, it can be used to read objects of effective type int and const int.

like image 192
Chris Dodd Avatar answered Sep 18 '22 09:09

Chris Dodd


Have you tried to do like this:

int main(int argc, const char *argv[]) {     struct deneme mydeneme = { 15, 20 };     struct deneme *pmydeneme = malloc(sizeof(struct deneme));     memcpy(pmydeneme, &mydeneme , sizeof(mydeneme));     return 0; } 

I have not tested but the code seems correct

like image 42
FBruynbroeck Avatar answered Sep 21 '22 09:09

FBruynbroeck