sintaxis - Diferencias en la inicialización del registro EAX cuando se llama a una función en C y C++
sintaxis de c++ pdf (2)
Aparentemente es una medida defensiva, diseñada para situaciones en las que la función de fun
prototipos pasa a ser una función variada, como se explica por la respuesta de @ Jester.
Sin embargo, tenga en cuenta que esta explicación no contiene agua desde el punto de vista del lenguaje C estándar.
Desde el comienzo de los tiempos estandarizados (C89 / 90) el lenguaje C requería explícitamente que todas las funciones variadas se declararan con prototipo antes del punto de la llamada. Llamar a una función variadic no prototípica desencadena un comportamiento indefinido en el estándar C. Entonces, formalmente, los compiladores no tienen que dar cabida a la posibilidad de que la fun
sea variada; si lo es, el comportamiento no se definiría de todos modos.
Además, como señaló @John Bollinger en los comentarios, de acuerdo con el estándar C, una declaración no prototype int fun()
realidad impide más declaraciones de fun
de prototipos variados. Es decir, una función variadica no puede preestablecerse legalmente como una función ()
. Esa sería otra razón por la cual la declaración anterior no prototipo es suficiente para que el compilador asuma que la fun
no puede ser variada.
En realidad, esto podría ser una característica heredada, diseñada para admitir código C pre-estándar, donde no se requería la función predefinida de funciones variadas con prototipo.
Existe una curiosa diferencia entre los ensamblados de un programa pequeño, cuando se compila como un programa C o como un programa C ++ (para Linux x86-64).
El código en cuestión:
int fun();
int main(){
return fun();
}
Compilarlo como un C-programa (con gcc -O2
) produce:
main:
xorl %eax, %eax
jmp fun
Pero compilarlo como un programa C ++ - (con g++ -02
) produce:
main:
jmp _Z3funv
Me parece desconcertante que la versión C inicialice el valor de retorno de la función principal con 0
( xorl %eax, %eax
).
¿Qué característica del lenguaje C es responsable de esta necesidad?
Editar: Es cierto que, para int fun(void);
no hay inicialización del registro eax.
Si no hay ningún prototipo de fun
en absoluto, es decir:
int main(){
return fun();
}
luego el compilador C vuelve a cerrarse el registro eax.
En C int fun();
puede tomar cualquier número de argumentos, por lo que incluso puede ser una función varargs. Sin embargo, en C ++ significa que no requiere argumentos.
La convención x86-64 sysv abi exige que el registro AL
debe contener la cantidad de registros SSE utilizados al invocar una función varargs. Por supuesto, no pasa ningún argumento, por lo que se pone a cero. Por conveniencia, el compilador decidió poner a cero todo eax
. Declara tu prototipo como int fun(void);
y el xor
desaparecerá.