c – C别名规则和memcpy

前端之家收集整理的这篇文章主要介绍了c – C别名规则和memcpy前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在回答另一个问题时,我想到了以下例子:
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的函数,而不会破坏别名规则?

解决方法

C标准很清楚.由p命名的对象的有效类型为void *,因为它具有声明类型,请参见6.5 / 6. C99中的别名规则适用于读写,并且(1)中通过无符号lvalue写入void *是根据6.5 / 7的未定义行为.

相反,(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的区别是什么(该列表上的人不同意它是什么).

猜你在找的C&C++相关文章