我实现了阶乘函数的简单版本,它们都可以在这里看到。我正在使用GCC Trunk。有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;
}
现在,当我在本地PC上使用c++17
在我安装的IDE
Visual Studio 2017
中运行这些时,我得到了从main()
返回的预期输出,并且返回值对于两个实现都是正确的。
我将它移植到编译器资源管理器,以测试其他编译器和它们的优化,以比较它们生成的汇编指令。这是一个相当简单的过程。
现在当我像这样运行这些函数时:
源# 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
。
现在回答我的问题:
然而,在没有做一些寄存器数学的情况下,在第一个和第三个编译器的汇编中并不明显,但是在第二个和最后一个function
和template
版本都打开-O3
的情况下,值720
在main()
返回调用之前被存储到EAX
寄存器中。为什么编译器资源管理器显示:Program returned: 208
而不是720
?
main
被定义为返回int
。在main
返回后,c++运行时将使用main
返回的值调用std::exit
(或等效代码)。
std::exit
也接受int
退出码。如何将退出码转换为进程返回码由实现定义。
在Unix上,进程的返回码通常是一个无符号字节,因此int
被简单地截断以适合0
-255
。
在Windows上进程返回码是32位有符号整数,所以传递给std::exit
的int
值直接返回。