如果我不包含标题,为什么在调用函数之前清除 EAX?

问题描述

在以下 C 代码中:

#include <stdio.h>
int main(void){getchar();}

它产生以下汇编:

main:
        push    rbp
        mov     rbp,rsp
                 # no extra instruction here when header is included
        call    getchar
        mov     eax,0
        pop     rbp
        ret

但是,如果我不在文件中包含 stdio.h,那么它仍然可以编译,但会添加看起来像随机 mov eax,0 指令的内容

enter image description here

这是编译器资源管理器:https://godbolt.org/z/3fTcss。这只是“未定义行为”的一部分,还是有特殊原因将 call getchar 之前的指令添加到那里?

解决方法

如果没有标头,gcc 会在您使用它时提供getchar隐式声明,就像您之前声明过的一样

int getchar();

(此行为由旧版本的 C 标准保证。当前版本使使用先前未声明的函数成为未定义行为,但 gcc 仍提供旧行为作为扩展。)

此声明未提供有关 getchar 期望的参数类型的信息。 (请记住,与在 C++ 中不同的是,带有 () 的声明不会将函数声明为接受 no 参数,而是将其声明为接受 未指定 参数,将它留给程序员知道函数期望什么并传递正确数量和类型的参数。)对于所有编译器知道的,它甚至可以是可变参数,并且根据 x86-64 SysV ABI,可变参数函数期望在 al用于传递参数的向量寄存器的数量。这里没有使用向量寄存器,因此编译器在调用之前将 al 设置为 0。 (实际上将所有 rax 归零会更有效,因此它会这样做。)