我有这个简单的结构,我想在堆上初始化并作为函数中的指针返回。
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
复制到正确的位置?
答案 0 :(得分:4)
您提交的作业不正确,不应编译。
使用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;
答案 1 :(得分:2)
这一行:
*entry = (struct entry) { .key = key, .data = data, .next = NULL };
使用赋值运算符。赋值算子的条件(C11 6.5.16 / 2)包括:
<强>约束强>
赋值运算符应具有可修改的左值作为其左操作数。
可修改的左值的定义可以在6.3.2.1/1中找到:
可修改的左值是一个左值,它没有数组类型,没有不完整的类型,没有const限定类型,如果是结构或联合,则没有任何成员(包括,递归) ,具有const限定类型的所有包含聚合或联合的任何成员或元素。
所以*entry
不是可修改的左值,因为它的类型是一个具有const限定类型成员的结构。因此,{strong>约束违规会使*entry
出现在赋值运算符的左侧。
clang编译器(我试过的所有版本)似乎都没有为此约束违规提供任何诊断消息;这显然是一个编译器错误。 gcc确实给出了诊断。
关于问题的第二部分:
我应该更喜欢创建一个本地结构,然后用memcpy复制到正确的位置吗?
正如2501所解释的那样,在写入malloc
系列分配的空间时,可以在C中执行此操作。 (如果您已声明了一个名为struct entry
的对象,则不清楚是否允许memcpy
对象。