对堆上结构使用结构初始化语法
Use of struct initialization syntax for on-heap struct
我有一个简单的结构,我想在堆上初始化并return作为函数中的指针。
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
是一个常量指针。我在某个地方发现了这种有效的语法:
struct entry* entry = calloc(1, sizeof(struct entry));
*entry = (struct entry) { .key = key, .data = data, .next = NULL };
但我不知道它发生了什么:它是否创建了一个 "anonymous" 结构,然后将其复制到 *entry
所在的位置?使用它是否安全,或者我应该更喜欢创建一个本地结构,然后用 memcpy
将其复制到正确的位置?
您提交的作业不正确,不应编译。
用常量成员初始化分配的结构的正确方法是分配一些内存,创建一个临时结构入口对象,然后使用 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)包括:
Constraints
An assignment operator shall have a modifiable lvalue as its left operand.
可修改左值的定义可以参考6.3.2.1/1:
A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.
所以 *entry
不是一个可修改的左值,因为它的类型是一个结构体,它有一个具有 const 限定类型的成员。因此,约束违规 *entry
出现在赋值运算符的左侧。
clang 编译器(我尝试过的所有版本)似乎没有针对此约束违规给出任何诊断消息;这显然是一个编译器错误。 gcc 确实给出了诊断。
关于问题的第二部分:
should I prefer creating a local struct that is then copied with memcpy to the right location?
正如 2501 所解释的那样,您可以在写入由 malloc
系列分配的 space 时在 C 中执行此操作。 (如果您已经声明了一个命名的 struct entry
对象,那么是否允许 memcpy
访问它就不太清楚了)。
我有一个简单的结构,我想在堆上初始化并return作为函数中的指针。
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
是一个常量指针。我在某个地方发现了这种有效的语法:
struct entry* entry = calloc(1, sizeof(struct entry));
*entry = (struct entry) { .key = key, .data = data, .next = NULL };
但我不知道它发生了什么:它是否创建了一个 "anonymous" 结构,然后将其复制到 *entry
所在的位置?使用它是否安全,或者我应该更喜欢创建一个本地结构,然后用 memcpy
将其复制到正确的位置?
您提交的作业不正确,不应编译。
用常量成员初始化分配的结构的正确方法是分配一些内存,创建一个临时结构入口对象,然后使用 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)包括:
Constraints
An assignment operator shall have a modifiable lvalue as its left operand.
可修改左值的定义可以参考6.3.2.1/1:
A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.
所以 *entry
不是一个可修改的左值,因为它的类型是一个结构体,它有一个具有 const 限定类型的成员。因此,约束违规 *entry
出现在赋值运算符的左侧。
clang 编译器(我尝试过的所有版本)似乎没有针对此约束违规给出任何诊断消息;这显然是一个编译器错误。 gcc 确实给出了诊断。
关于问题的第二部分:
should I prefer creating a local struct that is then copied with memcpy to the right location?
正如 2501 所解释的那样,您可以在写入由 malloc
系列分配的 space 时在 C 中执行此操作。 (如果您已经声明了一个命名的 struct entry
对象,那么是否允许 memcpy
访问它就不太清楚了)。