如何在C中的结构中初始化const(使用malloc)

我试过了;

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; } 

这是编译器的错误:

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

而且,这也是;

 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; } 

这是编译器的错误:

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

而且都没有汇编。 有没有办法在使用malloc分配内存时初始化struct内的const变量?

你需要抛弃const来初始化malloc结构的字段:

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

或者,您可以创建结构的初始化版本并对其进行memcpy:

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

如果你经常这样做,你可以使deneme_init静态和/或全局(所以它只需要构建一次)。


使用C11标准引用解释为什么此代码不是某些注释所建议的未定义行为:

  • 此代码不违反6.7.3 / 6,因为malloc返回的空间不是“使用const限定类型定义的对象”。 表达式mydeneme->a不是一个对象,它是一个表达式。 虽然它具有const限定类型,但它表示一个未使用const限定类型定义的对象(事实上,根本没有定义任何类型)。

  • 写入malloc分配的空间永远不会违反严格别名规则,因为每次写入都会更新有效类型 (6.5 / 6)。

(但是,可以通过从malloc分配的空间读取来违反严格的别名规则)。

在Chris的代码示例中,第一个将整数值的有效类型设置为int ,第二个将有效类型设置为const int ,但是在这两种情况下继续通过*mydeneme读取这些值是正确的,因为*mydeneme别名规则(6.5 / 7 bullet 2)允许通过表达式读取对象,该表达式与对象的有效类型相同或更有资格。 由于表达式mydeneme->a类型为const int ,因此它可用于读取有效类型为intconst int

你试过这样做:

 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; } 

我没有测试,但代码似乎是正确的

我不同意基督多德的回答,因为我认为他的解决方案根据标准给出了未定义的行为 ,正如其他人所说的那样。

为了以不调用未定义行为的方式“解决” const限定符,我提出以下解决方案:

  1. 定义使用malloc()调用初始化的void*变量。
  2. 定义所需类型的对象,在本例中为struct deneme ,并以某种方式初始化const限定符不会抱怨(即,在声明行本身中)。
  3. 使用memcpy()struct deneme对象的位复制到void*对象。
  4. 声明一个指向struct deneme对象的指针,并将其初始化为之前转换为(struct deneme *)(void*)变量。

所以,我的代码是:

 #include  #include  #include  struct deneme { const int a; const int b; }; struct deneme* deneme_init(struct deneme data) { void *x = malloc(sizeof(struct deneme)); memcpy(x, &data, sizeof(struct deneme)); return (struct deneme*) x; } int main(void) { struct deneme *obj = deneme_init((struct deneme) { 15, 20, } ); printf("obj->a: %d, obj->b: %d.\n", obj->a, obj->b); return 0; } 

有趣的是我发现这种C99方式在clang中工作但在gcc中没有

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