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
但是,如果以后存在p的使用,则可能会导致根据位模式导致的未定义的行为.如果没有这样的用途,那么该代码在C. 根据我认为在这个问题上并不清楚的“C标准”,我认为以下是这样.请不要以这种解释为唯一可能 – 模糊/不完整的规定留下了很大的投机空间. 线(1)是有问题的,因为& p的对齐可能不符合无符号类型.它将存储在p中的对象的类型更改为unsigned int.只要您不通过p访问该对象,则别名规则不会中断,但是对齐要求可能仍然存在. 然而,线(2)没有对齐问题,因此只要你不以后访问p作为void *,这可能会导致未定义的行为,这取决于void *类型如何解释存储的位模式.我不认为对象的类型因此而改变. 有一个长的GCC Bugreport还讨论了通过这样一个演员造成的指针的写入的影响,以及与placement-new的区别是什么(该列表上的人不同意它是什么). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |