为什么编译器为const int和vs const int参数生成不同的代码?

Pra*_*tic 1 c++ assembly g++ language-lawyer

考虑这两个功能.

int foo(const int& a) {
    return a + 5;
}

int bar(const int a) {
    return a + 5;
}
Run Code Online (Sandbox Code Playgroud)

给定这些函数,g ++ - 4.9在完全优化时生成以下代码.

g++-4.9 -std=c++11 -Ofast -march=native -DNDEBUG -fno-exceptions -Wall -S -o test17.S test17.cpp
Run Code Online (Sandbox Code Playgroud)
# foo
movl    (%rdi), %eax
addl    $5, %eax
ret

# bar
leal    5(%rdi), %eax
ret
Run Code Online (Sandbox Code Playgroud)

这台机器是x86-64 Mac.

为什么编译器在这里"文字化"?

我的理解是,C++中的引用通常是作为指针实现的,但这并不是标准规定的.它们最好被理解为变量的别名.详细信息留待实施.

鉴于引用实际上不需要指针,为两个函数生成相同的代码似乎是一个明显的优化.生成这const int两个函数的代码是否合法?这两个函数之间是否存在可观察到的差异?

AnT*_*AnT 9

您通过外部链接声明了您的功能.没有(或不能)执行全局程序优化的编译器不能改变具有外部链接的函数的接口规范,原因显而易见 - 该函数可以从其他一些翻译单元调用,该单元不知道函数的接口规范是否为"改变了"或不改变.

如果使用内部链接声明这些函数,则编译器可以更自由地转换这些函数.

当我声明你的函数static并编译它们时gcc -O3 -fno-inline-functions -fno-inline-functions-called-once -fno-inline-small-functions(在绝望的无限制尝试中杀死任何内联的可能性),它们产生相同的代码

_ZL3bari:
.LFB1:
    .seh_endprologue
    leal    5(%rcx), %eax
    ret

_ZL3fooRKi.isra.0:
.LFB3:
    .seh_endprologue
    leal    5(%rcx), %eax
    ret
Run Code Online (Sandbox Code Playgroud)

请注意,这些注意事项仅适用于"普通"函数(这可能是您首先所说的)与"明显"(对编译器)语义."非平凡"功能可能会抛弃参考的常量并修改裁判,如果裁判本身是可修改的,则完全合法.因此,在一般情况下,不可能用值参数替换const引用参数.