void *p; unsigned x = 17; assert(sizeof(void*) >= sizeof(unsigned)); *(unsigned*)&p = 17; // (1) memcpy(&p,&x,sizeof(x)); // (2)
第1行打破混叠规则.然而,第2行是OK wrt.混叠规则.问题是:为什么?编译器是否具有关于memcpy等功能的特殊内置知识,还是有一些使memcpy OK的其他规则?有没有办法在标准C中实现类似memcpy的函数,而不会破坏别名规则?
解决方法
相反,(2)的memcpy是好的,因为unsigned char *可以别名任何对象(6.5 / 7).该标准将memcpy定义为7.21.2 / 1
For all functions in this subclause,each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).
The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1. If copying takes place between objects that overlap,the behavior is undefined.
但是,如果以后存在p的使用,则可能会导致根据位模式导致的未定义的行为.如果没有这样的用途,那么该代码在C.
根据我认为在这个问题上并不清楚的“C标准”,我认为以下是这样.请不要以这种解释为唯一可能 – 模糊/不完整的规定留下了很大的投机空间.
线(1)是有问题的,因为& p的对齐可能不符合无符号类型.它将存储在p中的对象的类型更改为unsigned int.只要您不通过p访问该对象,则别名规则不会中断,但是对齐要求可能仍然存在.
然而,线(2)没有对齐问题,因此只要你不以后访问p作为void *,这可能会导致未定义的行为,这取决于void *类型如何解释存储的位模式.我不认为对象的类型因此而改变.
有一个长的GCC Bugreport还讨论了通过这样一个演员造成的指针的写入的影响,以及与placement-new的区别是什么(该列表上的人不同意它是什么).