对堆上结构

时间:2016-04-20 17:35:53

标签: c struct initialization heap-memory

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

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复制到正确的位置?

2 个答案:

答案 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对象。