我想在堆上分配一个结构,初始化它并从函数返回指向它的指针。我想知道在这种情况下是否有办法初始化结构体的 const 成员:
#include <stdlib.h>
typedef struct {
const int x;
const int y;
} ImmutablePoint;
ImmutablePoint * make_immutable_point(int x, int y)
{
ImmutablePoint *p = (ImmutablePoint *)malloc(sizeof(ImmutablePoint));
if (p == NULL) abort();
// How to initialize members x and y?
return p;
}
我是否应该由此得出结论,不可能在包含 const 成员的堆上分配和初始化一个结构体?
像这样:
ImmutablePoint *make_immutable_point(int x, int y)
{
ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
if (p == NULL) abort();
memcpy(p, &init, sizeof *p);
return p;
}
(请注意,与 C++ 不同,在 C 中不需要强制转换
malloc
的返回值,并且它通常被认为是不好的形式,因为它可以隐藏其他错误)。
如果这是 C 而不是 C++,我认为除了颠覆类型系统之外没有其他解决方案。
ImmutablePoint * make_immutable_point(int x, int y)
{
ImmutablePoint *p = malloc(sizeof(ImmutablePoint));
if (p == NULL) abort();
// this
ImmutablePoint temp = {x, y};
memcpy(p, &temp, sizeof(temp));
// or this
*(int*)&p->x = x;
*(int*)&p->y = y;
return p;
}
如果你坚持在结构中保留常量,你将不得不进行一些转换来解决这个问题:
int *cheat_x = (int *)&p->x;
*cheat_x = 3;
我喜欢caf的做法,但这也发生在我身上
ImmutablePoint* newImmutablePoint(int x, int y){
struct unconstpoint {
int x;
int y;
} *p = malloc(sizeof(struct unconstpoint));
if (p) { // guard against malloc failure
*p.x = x;
*p.y = y;
}
return (ImmutablePoint*)p;
}
为了扩展已接受的答案,允许这样做的原因:
ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
memcpy(p, &init, sizeof *p);
是因为
malloc
返回的内存(或更准确地说,返回的对象)没有有效类型,因此允许写入。 那么一旦使用memcpy
复制到源对象中,分配对象的有效类型就变成了ImmutablePoint
。
这在 C 标准第 6.5p6 节中有详细说明:
访问其存储值的对象的有效类型是 对象的声明类型(如果有)。 87) 如果一个值为 通过左值存储到没有声明类型的对象中 非字符类型的类型,则为左值的类型 成为该访问的对象的有效类型 后续访问不会修改存储的值。 如果一个值为 使用
或memcpy
复制到没有声明类型的对象中, 或者被复制为字符类型的数组,那么有效类型 该访问和后续访问的修改对象 不修改该值是对象的有效类型 如果有值,则复制该值。 对于对某个值的所有其他访问 没有声明类型的对象,该对象的有效类型是 只是用于访问的左值的类型。memmove
87) 分配的对象没有声明类型。