-O1 -O2(内联)的奇怪行为

问题描述 投票:0回答:1

这是我的代码:

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 但它消失了,为什么?

c inline
1个回答
4
投票

编译器可能通过在

three
中内联
main
的调用来优化这一点。那么,实际上,
main
有语句
3;
。该语句没有明显的效果,因此编译器通过删除它来进一步优化。那么
main
仅包含
return 0;
,因此编译器会为此生成代码,而不会生成其他代码。

优化程序时,编译器只需要考虑可观察行为,即根据 C 2018 5.1.2.3 6,仅考虑输入输出交互、写入文件的数据以及对

volatile
对象的访问:

— 对易失性对象的访问严格按照抽象机的规则进行评估。

— 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。

— 交互设备的输入和输出动态应按照 7.21.3 的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保提示消息实际出现在程序等待输入之前。

仅将 3 放入寄存器不会是可观察到的行为,因此编译器不需要保留它。

© www.soinside.com 2019 - 2024. All rights reserved.