对堆上结构使用struct初始化语法

我有这个简单的结构,我想在堆上初始化并作为函数中的指针返回。

struct entry { const char* const key; // We don't want the key modified in any way const void* data; // But the pointer to data can change struct entry* next; }; 

有一个问题,我不能calloc它并逐个初始化成员因为key是一个const指针。 我找到了一个有效的语法:

 struct entry* entry = calloc(1, sizeof(struct entry)); *entry = (struct entry) { .key = key, .data = data, .next = NULL }; 

但我不知道它发生了什么:它是否创建了一个“匿名”结构,然后将其复制到*entry所在的位置? 这是安全的,还是我更喜欢创建一个本地结构,然后用memcpy复制到正确的位置?

您提交的作业不正确,不应编译。

使用const成员初始化已分配结构的正确方法是分配一些内存,创建临时struct entry对象,然后使用memcpy将对象复制到分配的内存:

 void* mem = malloc( sizeof( struct entry ) ); struct entry temp = { key , data , NULL }; memcpy( mem , &temp , sizeof( temp ) ); struct entry* e = mem; 

这一行:

 *entry = (struct entry) { .key = key, .data = data, .next = NULL }; 

使用赋值运算符。 赋值算子的条件(C11 6.5.16 / 2)包括:

约束

赋值运算符应具有可修改的左值作为其左操作数。

可修改左值的定义可以在6.3.2.1/1中找到:

可修改的左值是一个左值,它没有数组类型,没有不完整的类型,没有const限定类型,如果是结构或联合,则没有任何成员(包括,递归地,任何成员)或具有const限定类型的所有包含的聚合或联合的元素。

因此*entry不是可修改的左值,因为它的类型是一个具有const限定类型的成员的结构。 因此,在赋值运算符的左侧出现*entry违反约束的

clang编译器(我尝试过的所有版本)似乎都没有为此约束违规提供任何诊断消息; 这显然是一个编译器错误。 gcc确实给出了诊断。


关于问题的第二部分:

我是否应该更喜欢创建一个本地结构,然后将其与memcpy一起复制到正确的位置?

正如2501所解释的那样,在写入malloc系列分配的空间时,可以在C中执行此操作。 (如果您已经声明了一个命名的struct entry对象,那么是否允许对其进行memcpy则不太清楚)。