这是这个问题的后续。
在解释我的问题时,我声明分配的内存可以重用,因为它没有声明的类型,并且我被告知它是不正确的 C。
下面是说明该问题的代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
struct Elt {
int id;
char name[32];
};
struct Elt2 {
double val;
char name[16];
};
static_assert(sizeof(struct Elt2) < sizeof(struct Elt), "Incorrect sizes");
int main() {
struct Elt actual1 = { 1, "foo"};
struct Elt2 actual2 = {2.0, "bar"};
struct Elt* elt = malloc(sizeof(struct Elt));
memcpy(elt, &actual1, sizeof(*elt)); // populates the allocated memory
printf("elt: %d %sn", elt->id, elt->name);
struct Elt2 *elt2 = (void *) elt; // declares a new pointer to a shorter type
memcpy(elt2, &actual2, sizeof(*elt2)); // effective type is now struct Elt2
printf("elt2: %g %sn", elt2->val, elt2->name);
//printf("elt: %d %sn", elt->id, elt->name); UB: storage now contains an Elt2 object
free(elt); // only legal use for elt
return 0;
}
我相信 n1570 草案的 6.5 表达式 §6 允许它:
用于访问其存储值的对象的有效类型是声明的类型 对象,如果有的话.87) 如果值通过 左值的类型不是字符类型,则左值的类型变为 该访问和不修改的后续访问的对象的有效类型 存储的值。如果将值复制到没有声明类型的对象中使用 memcpy 或 memmove,或被复制为字符类型的数组,然后是有效类型 该访问的修改对象以及不修改 值是从中复制值的对象的有效类型(如果有)。
附注87:
87) 分配的对象没有声明的类型。
问题:
重用分配的内存来存储可以放入该内存的不同对象是否符合 C?
如果没有,那将是灾难性的。许多人使用这样的技巧来实现自己的细粒度内存管理,以malloc
。
所以,是的,这正是您引用的标准中的段落的内容。请注意,它仔细选择了单词。它说
如果将值存储到没有声明类型的对象中...
没有声明类型的此属性在对象的生存期内不会更改,因此该规定在将新值写入其中时随时适用。
如果出于某种奇怪的原因,委员会想说有效类型只能更改一次,他们会说类似
如果将值存储到没有有效类型的对象中...
唯一正确的答案是完全从标准中得出的答案。
在不通过标准的情况下,我会说,"是的,你的假设是正确的"。我这么说是因为没有它,就不可能实现自己的内存管理器。我认为如果没有它,甚至malloc
都无法在 C 中实现。