如果我不包含 header,为什么在调用函数之前清除 EAX?
Why is EAX being cleared before calling a function if I don't include the header?
在以下 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
指令的内容:
这是编译器资源管理器:https://godbolt.org/z/3fTcss。这只是“未定义行为”的一部分,还是有特殊原因将 call getchar
之前的指令添加到那里?
在没有 header 的情况下,gcc 会在您使用 getchar
时提供 隐式声明 ,就像您之前声明过
int getchar();
(此行为由旧版本的 C 标准保证。当前版本使使用以前未声明的函数成为未定义行为,但 gcc 仍提供旧行为作为扩展。)
此声明未提供有关 getchar
期望的参数类型的信息。 (请记住,与 C++ 不同,带有 ()
的声明不会将函数声明为采用 no 参数,而是采用 unspecified参数,让程序员知道函数期望什么并传递适当数量和类型的参数。)对于所有编译器所知,它甚至可以是可变参数,并且根据 x86-64 SysV ABI,可变参数函数期望在al
用于传递参数的向量寄存器的数量。这里没有使用向量寄存器,因此编译器在调用之前将 al
设置为 0
。 (实际上将所有 rax
清零效率稍高,所以它改为这样做。)
在以下 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
指令的内容:
这是编译器资源管理器:https://godbolt.org/z/3fTcss。这只是“未定义行为”的一部分,还是有特殊原因将 call getchar
之前的指令添加到那里?
在没有 header 的情况下,gcc 会在您使用 getchar
时提供 隐式声明 ,就像您之前声明过
int getchar();
(此行为由旧版本的 C 标准保证。当前版本使使用以前未声明的函数成为未定义行为,但 gcc 仍提供旧行为作为扩展。)
此声明未提供有关 getchar
期望的参数类型的信息。 (请记住,与 C++ 不同,带有 ()
的声明不会将函数声明为采用 no 参数,而是采用 unspecified参数,让程序员知道函数期望什么并传递适当数量和类型的参数。)对于所有编译器所知,它甚至可以是可变参数,并且根据 x86-64 SysV ABI,可变参数函数期望在al
用于传递参数的向量寄存器的数量。这里没有使用向量寄存器,因此编译器在调用之前将 al
设置为 0
。 (实际上将所有 rax
清零效率稍高,所以它改为这样做。)