在 Compiler Explorer 上比较函数和函数模板之间的输出

Comparing the outputs between a function and a function template on Compiler Explorer

我实现了阶乘函数的简单版本,两者都可以看到 here。我正在使用 GCC T运行k。有 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;
}

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

我将其移植到 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          |
    

一切都很好。

所有四个程序执行return一个值208

现在回答我的问题:

然而,在第一个和第三个编译器的汇编中,如果不做一些寄存器数学运算,这并不明显,但是在第二个也是最后一个,-O3functiontemplate 版本,值 720main() 的 return 调用之前被存储到 EAX 寄存器中。为什么编译器资源管理器显示:Program returned: 208 而不是 720

main 定义为 return 和 int。在 main returns 之后,c++ 运行时将使用 main.

中的值 return 调用 std::exit(或等效代码)

std::exit 也需要一个 int 退出代码。这个退出代码如何变成一个进程return代码是实现定义的。

在 Unix 上,进程的 return 代码通常是单个无符号字节,因此 int 被简单地截断以适应 0 - 255.

在 Windows 过程中 return 代码是 32 位有符号整数,因此传递给 std::exitint 值直接 returned。