C标准对此非常清楚。由 命名的对象的有效类型p
是void*
,因为它具有声明的类型,请参见6.5/6
。C99中的别名规则适用于读取和写入,根据.void*
unsigned
(1)
6.5/7
相反,memcpy
of(2)
很好,因为unsigned char*
可以为任何对象 ( ) 起别名6.5/7
。该标准定义memcpy
为7.21.2/1
对于本子条款中的所有函数,每个字符都应被解释为好像它具有 unsigned char 类型(因此每个可能的对象表示都是有效的并且具有不同的值)。
memcpy 函数将 n 个字符从 s2 指向的对象复制到 s1 指向的对象中。如果复制发生在重叠的对象之间,则行为未定义。
但是,如果之后存在使用p
,则可能会导致未定义的行为,具体取决于位模式。如果没有发生这样的使用,那么该代码在 C 中是可以的。
根据C++ Standard,我认为这个问题还很不清楚,我认为以下内容成立。请不要将此解释视为唯一可能的解释 - 模糊/不完整的规范留下了很大的猜测空间。
行(1)
是有问题的,因为该类型的对齐&p
可能不合适unsigned
。它将存储的对象的类型更改p
为unsigned int
. 只要您以后不通过 访问该对象p
,别名规则就不会被破坏,但对齐要求可能仍然存在。
但是, Line(2)
没有对齐问题,因此是有效的,只要您p
以后不作为 a访问void*
,这可能会导致未定义的行为,具体取决于void*
类型如何解释存储的位模式。我不认为对象的类型因此而改变。
有一个很长的GCC Bugreport还讨论了通过这种转换产生的指针写入的含义以及与placement-new 的区别是什么(该列表上的人不同意它是什么)。