在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版本用0
( xorl %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
将消失。
显然它是一种防御措施,专为无原型fun
function实际上是一种可变函数的情况而设计,正如@Jester的回答所解释的那样。
请注意,从标准C语言的角度来看,这种解释并没有任何用处。
自标准化时间(C89 / 90)开始以来,C语言明确要求所有可变参数函数在调用之前用原型声明。 调用非原型的可变参数函数会在标准C中触发未定义的行为。因此,正式地,编译器不必容纳变量的可能性 – 如果是,则行为将无论如何都是未定义的。
此外,正如@John Bollinger在评论中指出的那样,根据C标准,非原型int fun()
声明实际上排除了进一步的变量原型声明的fun
。 即变量函数不能合法地预先声明为a ()
函数。 这就是为什么上面的非原型声明足以让编译器认为fun
不可能是变量的另一个原因。
这实际上可能是一个遗留function,旨在支持预标准C代码,其中不需要使用原型预先声明可变参数函数。