-
小怪兽爱吃肉
我发现的最佳解释是Mike Acton,了解严格别名。它主要关注PS3开发,但这基本上只是GCC。来自文章:“严格别名是由C(或C ++)编译器做出的一个假设,即取消引用指向不同类型对象的指针永远不会引用相同的内存位置(即彼此别名)。”所以基本上如果你有一个int*指向包含一个内存的内存int然后你指向一个float*内存并将其用作float你打破规则。如果您的代码不遵守这一点,那么编译器的优化器很可能会破坏您的代码。规则的例外是a char*,允许指向任何类型。
-
慕容3067478
这是严格的别名规则,可以在C ++ 03标准的3.10节中找到(其他答案提供了很好的解释,但没有提供规则本身):如果程序试图通过不同于以下类型之一的左值访问对象的存储值,则行为未定义:对象的动态类型,一个cv限定版本的动态类型的对象,与对象的动态类型对应的有符号或无符号类型的类型,一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),一个类型,它是对象动态类型的(可能是cv限定的)基类类型,a char或unsigned char类型。C ++ 11和C ++ 14措辞(强调变化):如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:对象的动态类型,一个cv限定版本的动态类型的对象,与对象的动态类型类似的类型(如4.4中所定义),与对象的动态类型对应的有符号或无符号类型的类型,一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),一个类型,它是对象动态类型的(可能是cv限定的)基类类型,a char或unsigned char类型。两个变化很小:glvalue而不是lvalue,以及聚合/联合案例的澄清。第三个变化提供了更强有力的保证(放宽强混叠规则):类似类型的新概念现在可以安全别名。另外,Ç措词(C99; ISO / IEC 9899:1999 6.5 / 7;完全相同的措词在ISO / IEC 9899中使用:2011§6.5¶7):对象的存储值只能由具有以下类型之一(73)或88)的左值表达式访问:与对象的有效类型兼容的类型,与对象的有效类型兼容的类型的限定版本,与对象的有效类型对应的有符号或无符号类型的类型,与有效类型的对象的限定版本对应的有符号或无符号类型的类型,聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),或者一个字符类型。73)或88)此列表的目的是指定对象可能或可能不具有别名的情况。
-
拉风的咖菲猫
严格的别名不仅仅指向指针,它也会影响引用,我为boost开发人员wiki写了一篇关于它的文章,并且它很受欢迎,我把它变成了我咨询网站上的一个页面。它完全解释了它是什么,为什么它如此混淆了人们以及如何处理它。严格别名白皮书。特别是它解释了为什么工会是C ++的危险行为,以及为什么使用memcpy是C和C ++中唯一可移植的解决方案。希望这是有帮助的。
-
绝地无双
作为Doug T.已经写过的补充,这里有一个简单的测试用例,可能用gcc触发它:check.c#include <stdio.h>void check(short *h,long *k){
*h=5;
*k=6;
if (*h == 5)
printf("strict aliasing problem\n");}int main(void){
long k[1];
check((short *)k,k);
return 0;}编译gcc -O2 -o check check.c。通常(我尝试过的大多数gcc版本)都输出“严格别名问题”,因为编译器假定“h”不能与“check”函数中的“k”相同。因此,编译器优化了if (*h == 5)远离并始终调用printf。对于那些感兴趣的人是x64汇编程序代码,由gcc 4.6.3生成,在ubuntu 12.04.2 for x64上运行:movw $5, (%rdi)movq $6, (%rsi)movl $.LC0, %edi
jmp puts所以if条件完全从汇编代码中消失了。