为了账号安全,请及时绑定邮箱和手机立即绑定

什么是严格别名规则?

什么是严格别名规则?

四季花海 2019-05-21 14:50:30
当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明。他们在说什么?
查看完整描述

5 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

我发现的最佳解释是Mike Acton,了解严格别名。它主要关注PS3开发,但这基本上只是GCC。

来自文章:

“严格别名是由C(或C ++)编译器做出的一个假设,即取消引用指向不同类型对象的指针永远不会引用相同的内存位置(即彼此别名)。”

所以基本上如果你有一个int*指向包含一个内存的内存int然后你指向一个float*内存并将其用作float你打破规则。如果您的代码不遵守这一点,那么编译器的优化器很可能会破坏您的代码。

规则的例外是a char*,允许指向任何类型。


查看完整回答
反对 回复 2019-05-21
?
慕容3067478

TA贡献1773条经验 获得超3个赞

这是严格的别名规则,可以在C ++ 03标准的3.10节中找到(其他答案提供了很好的解释,但没有提供规则本身):

如果程序试图通过不同于以下类型之一的左值访问对象的存储值,则行为未定义:

  • 对象的动态类型,

  • 一个cv限定版本的动态类型的对象,

  • 与对象的动态类型对应的有符号或无符号类型的类型,

  • 一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,

  • 一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),

  • 一个类型,它是对象动态类型的(可能是cv限定的)基类类型,

  • charunsigned char类型。

C ++ 11C ++ 14措辞(强调变化):

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

  • 对象的动态类型,

  • 一个cv限定版本的动态类型的对象,

  • 与对象的动态类型类似的类型(如4.4中所定义),

  • 与对象的动态类型对应的有符号或无符号类型的类型,

  • 一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,

  • 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),

  • 一个类型,它是对象动态类型的(可能是cv限定的)基类类型,

  • charunsigned char类型。

两个变化很小:glvalue而不是lvalue,以及聚合/联合案例的澄清。

第三个变化提供了更强有力的保证(放宽强混叠规则):类似类型的新概念现在可以安全别名。


另外,Ç措词(C99; ISO / IEC 9899:1999 6.5 / 7;完全相同的措词在ISO / IEC 9899中使用:2011§6.5¶7):

对象的存储值只能由具有以下类型之一(73)或88)的左值表达式访问:

  • 与对象的有效类型兼容的类型,

  • 与对象的有效类型兼容的类型的限定版本,

  • 与对象的有效类型对应的有符号或无符号类型的类型,

  • 与有效类型的对象的限定版本对应的有符号或无符号类型的类型,

  • 聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),或者

  • 一个字符类型。

73)或88)此列表的目的是指定对象可能或可能不具有别名的情况。


查看完整回答
反对 回复 2019-05-21
?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

严格的别名不仅仅指向指针,它也会影响引用,我为boost开发人员wiki写了一篇关于它的文章,并且它很受欢迎,我把它变成了我咨询网站上的一个页面。它完全解释了它是什么,为什么它如此混淆了人们以及如何处理它。严格别名白皮书。特别是它解释了为什么工会是C ++的危险行为,以及为什么使用memcpy是C和C ++中唯一可移植的解决方案。希望这是有帮助的。


查看完整回答
反对 回复 2019-05-21
?
绝地无双

TA贡献1946条经验 获得超4个赞

作为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条件完全从汇编代码中消失了。


查看完整回答
反对 回复 2019-05-21
  • 5 回答
  • 0 关注
  • 814 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信