对堆上结构使用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
则不太清楚)。