TL;DR公司
:在未优化的代码中,CLANG++为返回值留出4个字节
main
并按照C++(包括C++11)标准将其设置为零。它生成了
主要的
不需要它的函数。这是未优化的副作用。通常,一个未优化的编译器会生成它可能需要的代码,然后就不再需要它了,而且也没有做任何事情来清理它。
因为您正在使用
-O0
对代码进行的优化非常少(
-O0级
可能会删除死代码等)。试图理解未优化代码中的工件通常是徒劳的。未优化代码的结果是额外的加载和存储以及原始代码生成的其他工件。
在这种情况下
主要的
是特别的,因为在C99/C11和C++中,标准有效地说,当到达
主要的
默认返回值为0。
The C11 standard
表示:
5.1.2.2.3程序终止
1如果main函数的返回类型是与int兼容的类型,则从
对main函数的初始调用等效于使用值调用exit函数
由main函数返回作为其参数;11)
到达终止的}
main函数返回值0
。如果返回类型与int不兼容,则
未指定返回到主机环境的终止状态。
这个
C++11 standard
表示:
3.6.1主要功能
5) main中的return语句具有离开main函数的效果(使用automatic
并使用返回值作为参数调用std::exit。
如果控制到达终点
在不遇到return语句的情况下,其效果是执行
return 0;
在CLANG++版本中,您使用的是未优化的64位代码,默认情况下,返回值0位于
dword ptr [rbp-4]
。
问题是,您的测试代码有点过于琐碎,无法看到这个默认返回值是如何发挥作用的。以下是一个更好的示例:
int main() {
int a = 3;
if (a > 3) return 5678;
else if (a == 3) return 42;
}
此代码有两个退出显式退出点,通过
return 5678
和
return 42;
但没有决赛
return
在函数末尾。如果
}
默认值为返回0。如果我们检查
godbolt output
我们看到:
main: # @main
push rbp
mov rbp, rsp
mov dword ptr [rbp - 4], 0 # Default return value of 0
mov dword ptr [rbp - 8], 3
cmp dword ptr [rbp - 8], 3 # Is a > 3
jle .LBB0_2
mov dword ptr [rbp - 4], 5678 # Set return value to 5678
jmp .LBB0_5 # Go to common exit point .LBB0_5
.LBB0_2:
cmp dword ptr [rbp - 8], 3 # Is a == 3?
jne .LBB0_4
mov dword ptr [rbp - 4], 42 # Set return value to 42
jmp .LBB0_5 # Go to common exit point .LBB0_5
.LBB0_4:
jmp .LBB0_5 # Extraneous unoptimized jump artifact
# This is common exit point of all the returns from `main`
.LBB0_5:
mov eax, dword ptr [rbp - 4] # Use return value from memory
pop rbp
ret
可以看到,编译器生成了一个设置返回值的公共退出点(
EAX公司
)从堆栈地址
dword ptr[rbp-4]
。在代码开头
dword ptr[rbp-4]
显式设置为0。在更简单的情况下,未优化的代码仍然生成该指令,但没有使用。
如果使用选项构建代码
-ffreestanding
您应该看到的默认返回值
主要的
不再设置为0。这是因为
主要的
适用于主体环境,而非独立环境。