这是我的代码:
int three( void ) {
return 3;
}
int main( void ) {
three( );
return 0;
}
我想看看当我提高优化级别时,函数体是如何内联在代码中的。 我期望的是,他不会进行调用,而是将值 3 放入寄存器中,但事实并非如此,为什么?
gcc -O1 -S main.c -o O1.s
结果:
.file "main.c"
.text
.globl three
.type three, @function
three:
.LFB0:
.cfi_startproc
endbr64
movl $3, %eax
ret
.cfi_endproc
.LFE0:
.size three, .-three
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
endbr64
movl $0, %eax
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
-O1 但它消失了,为什么?
编译器可能通过在
three
中内联 main
的调用来优化这一点。那么,实际上,main
有语句3;
。该语句没有明显的效果,因此编译器通过删除它来进一步优化。那么 main
仅包含 return 0;
,因此编译器会为此生成代码,而不会生成其他代码。
优化程序时,编译器只需要考虑可观察行为,即根据 C 2018 5.1.2.3 6,仅考虑输入输出交互、写入文件的数据以及对
volatile
对象的访问:
— 对易失性对象的访问严格按照抽象机的规则进行评估。
— 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。
— 交互设备的输入和输出动态应按照 7.21.3 的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保提示消息实际出现在程序等待输入之前。
仅将 3 放入寄存器不会是可观察到的行为,因此编译器不需要保留它。