如何在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
,因此它可用于读取有效类型为int
和const 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
限定符,我提出以下解决方案:
- 定义使用
malloc()
调用初始化的void*
变量。 - 定义所需类型的对象,在本例中为
struct deneme
,并以某种方式初始化const
限定符不会抱怨(即,在声明行本身中)。 - 使用
memcpy()
将struct deneme
对象的位复制到void*
对象。 - 声明一个指向
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; }