1

我实现了阶乘函数的简单版本,两者都可以在这里看到。我正在使用 GCC 中继。有2个源文件,第一个是函数版本,第二个是模板版本。每个源文件都有 2 个附加的编译器和一个相关的输出。每个源文件的两个附加编译器之间的唯一区别是左侧编译器没有打开编译器标志或优化,而右侧版本已-O3设置为打开 3 级优化。

这是我的功能:

// Function Version
int factorial(int n) {
    if (n == 0 || n == 1) return 1;
    if (n == 2) return 2;
    return (n * factorial(n-1));
}

// Template Version:
template<unsigned N>
static auto constexpr factorial_t() {
    return (N * factorial<N-1>());
}

template<>
auto constexpr factorial_t<0>() {
    return 1;
}
template<>
auto constexpr factorial_t<1>() {
    return 1;
}
template<>
auto constexpr factorial_t<2>() {
    return 2;
}

现在,当我IDE Visual Studio 2017使用 安装在本地 PC 上运行这些时c++17,我得到了从 返回的预期输出main(),并且返回的值对于两种实现都是正确的。

我将此移植到 Compiler Explorer 以测试其他编译器及其优化,以比较它们生成的汇编指令。这是一个相当简单的过程。

现在,当我这样运行这些函数时:

来源#1

int main() {
    return factorial(6);
}

来源#2

int main() {
    return factorial_t<6>();
}

编译器资源管理器生成以下指令计数...

  •          |   Assembly Instruction Count   |
    
  • Type     | Without O3 | With O3 Turned On |  
    
  • Function |     34     |       29          |
    
  • Template |     50     |        3          |
    

一切都很好。

所有四个程序执行都返回一个值208

现在我的问题:

但是,在第一个和第三个编译器的程序集中直接在没有进行一些寄存器数学运算的情况下并不明显,但是在第二个和最后一个编译器中,对于和版本-O3都打开了,该值在' 的返回调用之前被存储到寄存器中。为什么编译器资源管理器显示:而不是?functiontemplate720EAXmain()Program returned: 208720

4

1 回答 1

3

main被定义为返回一个int. 返回后main,c++ 运行时将std::exit使用从main.

std::exit也需要一个int退出代码。如何将此退出代码转换为进程返回代码是实现定义的。

在 Unix 上,进程的返回码通常是单个无符号字节,因此它int被简单地截断以适合0- 255

在 Windows 进程返回码是 32 位有符号整数,因此int传递给的值std::exit直接返回。

于 2021-02-12T08:27:44.370 回答