您似乎对“有效类型”的适用范围感到困惑:它适用于 malloc 空间,而不是任何指针。与 C 中一样,指针是一个单独的对象,具有指向指针可能指向的任何空间的单独属性。
f
是一个(命名)变量,因此其有效类型始终与其声明类型相同,即Foo *
。相似地buf
的有效类型始终是char *
。有效类型在运行时可能改变的唯一一次是动态分配的空间。
您的要点和代码注释没有什么意义,因此我决定重新注释您的代码。在每种情况下,文本均指文本上方的代码:
Foo *f = malloc(sizeof(Foo));
好的。未初始化的字节已被分配并且f
指向他们。动态分配的空间还没有有效的类型。
f->n = 1;
第一种有效类型sizeof(int)
动态分配空间的字节设置为int
。 (* - 但请参阅脚注)
char *buf = malloc(sizeof(Foo));
memcpy(buf, f, sizeof(Foo));
The memcpy
函数保留复制对象的有效类型,因此第一个对象的有效类型sizeof(int)
指向的空间的字节数buf
, is int
.
((Foo *)buf)->n++;
首先,演员阵容不存在对齐问题,因为malloc
对于任何类型,空间都正确对齐。继续访问n
,这是可以的,因为((Foo *)buf)->n
是类型的左值int
,它指定一个有效类型的对象int
。这样我们就可以毫无问题地读写。
memcpy(f, buf, sizeof(Foo));
memcpy
总是可以的,因为它设置了有效类型(您的评论表明 memcpy 在某些情况下可能不正常)。该行设置了所指向的空间的有效类型f
, to int
(因为源空间具有有效类型int
).
f->n++;
很好,道理一样((Foo *)buf)->n++
above.
free(buf);
buf = (void *)f;
冗余演员阵容。所指向的空间f
有有效类型int
尽管如此,因为这两行都没有写入该空间。
free(f);
没问题。
脚注:有些人对这个表达有不同的解释f->n
(or ((Foo *)buf)->n
w.r.t.严格的别名。他们说f->n
定义为(*f).n
因此相关的有效类型是*f
,不是类型f->n
。我不同意这个观点,所以不再赘述。有人建议 C2X 澄清这种情况以及严格混叠的其他灰色区域。对于您的特定代码,该代码在任何一种解释下仍然是正确的。