【发布时间】:2018-01-02 11:34:44
【问题描述】:
编译器生成代码假定int 可以被unsigned int 别名。以下代码:
int f(int& a, unsigned int& b){
a=10;
b=12;
return a;
}
int f(int& a, double& b){
a=10;
b=12;
return a;
}
使用 Clang5 生成以下程序集(类似代码由 GCC 或 ICC 生成):
f(int&, unsigned int&): # @f(int&, unsigned int&)
mov dword ptr [rdi], 10
mov dword ptr [rsi], 12
mov eax, dword ptr [rdi] #return value must be loaded since rdi might equal rsi
ret
f(int&, double&): # @f(int&, double&)
mov dword ptr [rdi], 10
movabs rax, 4622945017495814144
mov qword ptr [rsi], rax
mov eax, 10 #return value is a direct value.
ret
在上面的示例中,如果b 和a 引用同一个对象,则在第一个重载f 中,返回值(在eax 寄存器中)为10 或12。在第二个重载中,a 和 b 不能引用同一个对象,因此返回值始终为 10。
严格的别名规则由 C++ 标准的这一段表达,[intro.object]/8:
[...] 如果一个对象嵌套在另一个对象中,则两个对象 a 和 b 具有重叠的生命周期且不是位域,它们可能具有相同的地址,或者如果至少有一个是零大小的基类子对象并且它们是不同的类型;否则,它们具有不同的地址。
所以根据这条规则,int 不能被 unsigned int 别名。
问题:
在 C++ 标准中是否存在允许
int别名为unsigned int的例外规则?如果不是,为什么所有编译器都假定这种可能性?
【问题讨论】:
-
严格的别名规则由 N4659 [basic.lval]/8 表示(标准版本中的点数不同),而不是 intro.object 。您引用的文字与严格的别名无关
-
@M.M.我认为严格的别名规则就是由此而来的。因此,答案中引用的段落导致我们可以从该段落中得出的规则的例外。我忽略了这一段。
-
intro.object/8 是在讨论两个对象的情况,而不是两个引用同一个对象的情况。实际标准对 a 和 b 使用斜体,而不是代码示例
a、b的字体;这些是抽象符号,表明我们正在谈论两个不同的对象,而不是两个表达式或其他任何东西
标签: c++ language-lawyer strict-aliasing