为什么以下结果没有错误?
void func()
{
func();
}
int main()
{
func();
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*lia 23
理论上,它会溢出堆栈(因为,即使没有使用局部变量,每次调用都会在堆栈上添加先前的返回地址); 实际上,在启用优化的情况下,它不会因为尾调用优化而溢出,这实际上避免了任何资源消耗在跳转中转换调用,因此不会消耗堆栈.
通过检查 OP代码生成的优化程序集,可以很容易地看出这一点:
func():
.L2:
jmp .L2
main:
.L4:
jmp .L4
Run Code Online (Sandbox Code Playgroud)
func被优化为无限循环,无论是"独立版本"还是内联调用main.
请注意,这与"as if"规则的C++标准一致:编译的程序必须像在代码中请求的那样运行(就效果而言),并且由于堆栈大小只是一个实现限制,生成的代码使用a call和使用a的代码jmp是等价的.
但是:这是一个更特殊的情况,因为标准甚至说无限循环(定义为 "不终止且没有一些副作用")实际上是未定义的行为,因此理论上编译器将被允许省略该调用完全.
它确实以我的Linux系统上的Segmentation故障结束- Valgrind指示可能的堆栈溢出,这当然是正确的,因为对于每个函数调用,需要一个新的堆栈帧.
但是,在编译器中启用优化会将整个程序减少到无限循环,这自然不会结束:
.file "so.c"
.text
.p2align 4,,15
.globl func
.type func, @function
func:
.LFB0:
.cfi_startproc
.p2align 4,,10
.p2align 3
.L2:
jmp .L2
.cfi_endproc
.LFE0:
.size func, .-func
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
.p2align 4,,10
.p2align 3
.L5:
jmp .L5
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (GNU) 4.4.3"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
这是有趣的部分:
.L5:
jmp .L5
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
785 次 |
| 最近记录: |