在C和C ++中调用函数时EAX寄存器初始化的差异

当编译为C程序或C ++程序(对于Linux x86-64)时,小程序的程序集之间存在奇怪的差异。

有问题的代码:

int fun(); int main(){ return fun(); } 

将其编译为C程序(使用gcc -O2 )可以得到:

 main: xorl %eax, %eax jmp fun 

但是将其编译为C ++程序(使用g++ -02 )会产生:

 main: jmp _Z3funv 

我觉得很困惑,C版本用0xorl %eax, %eax )初始化主函数的返回值。

C语言的哪个特性对这种必要性负责?

编辑:对于int fun(void);来说确实如此int fun(void); 没有初始化eax寄存器。

如果根本没有fun原型,即:

 int main(){ return fun(); } 

然后C编译器再次将eax寄存器归零。

在C int fun(); 可以采用任意数量的参数,因此它甚至可能是一个varargs函数。 但是在C ++中,它意味着它不需要参数。

x86-64 sysv abi约定要求寄存器AL必须包含调用varargs函数时使用的SSE寄存器的数量。 你当然不传递任何论据,所以它是归零的。 为方便起见,编译器决定将整个eax归零。 将你的原型声明为int fun(void);xor将消失。

显然它是一种防御措施,专为无原型funfunction实际上是一种可变函数的情况而设计,正如@Jester的回答所解释的那样。

请注意,从标准C语言的角度来看,这种解释并没有任何用处。

自标准化时间(C89 / 90)开始以来,C语言明确要求所有可变参数函数在调用之前用原型声明。 调用非原型的可变参数函数会在标准C中触发未定义的行为。因此,正式地,编译器不必容纳变量的可能性 – 如果是,则行为将无论如何都是未定义的。

此外,正如@John Bollinger在评论中指出的那样,根据C标准,非原型int fun()声明实际上排除了进一步的变量原型声明的fun 。 即变量函数不能合法地预先声明为a ()函数。 这就是为什么上面的非原型声明足以让编译器认为fun不可能是变量的另一个原因。

这实际上可能是一个遗留function,旨在支持预标准C代码,其中不需要使用原型预先声明可变参数函数。