【问题标题】:Can an int be aliased as an unsigned int? [duplicate]int 可以别名为 unsigned int 吗? [复制]
【发布时间】: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

在上面的示例中,如果ba 引用同一个对象,则在第一个重载f 中,返回值(在eax 寄存器中)为10 或12。在第二个重载中,ab 不能引用同一个对象,因此返回值始终为 10。

严格的别名规则由 C++ 标准的这一段表达,[intro.object]/8

[...] 如果一个对象嵌套在另一个对象中,则两个对象 ab 具有重叠的生命周期且不是位域,它们可能具有相同的地址,或者如果至少有一个是零大小的基类子对象并且它们是不同的类型;否则,它们具有不同的地址。

所以根据这条规则,int 不能被 unsigned int 别名。

问题:

  1. 在 C++ 标准中是否存在允许 int 别名为 unsigned int 的例外规则?

  2. 如果不是,为什么所有编译器都假定这种可能性?

【问题讨论】:

  • 严格的别名规则由 N4659 [basic.lval]/8 表示(标准版本中的点数不同),而不是 intro.object 。您引用的文字与严格的别名无关
  • @M.M.我认为严格的别名规则就是由此而来的。因此,答案中引用的段落导致我们可以从该段落中得出的规则的例外。我忽略了这一段。
  • intro.object/8 是在讨论两个对象的情况,而不是两个引用同一个对象的情况。实际标准对 ab 使用斜体,而不是代码示例 ab 的字体;这些是抽象符号,表明我们正在谈论两个不同的对象,而不是两个表达式或其他任何东西

标签: c++ language-lawyer strict-aliasing


【解决方案1】:

C++ 标准中的这条规则是否有一个例外,允许使用 unsigned int 对 int 进行别名处理?

是的,是[basic.lval]/8

如果程序尝试通过以下方式访问对象的存储值 行为是以下类型之一以外的左值 未定义:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多