c++ - compiler - gcc ultima version
Inicialización de cero extraño con g++ (6)
Me encontré con un extraño comportamiento del siguiente código, mientras jugaba con la inicialización de ints usando g ++ 4.4.3.
int main()
{
int x(int());
int y = int();
cout << x << " " << y << endl;
}
el resultado es:
1 0
El valor de "y" es 0 como se esperaba, pero el valor de x es extrañamente "1".
En VS2008 produce el siguiente error de enlace (una declaración de función, pero sin definición):
unresolved external symbol "int __cdecl x(int (__cdecl*)(void))"
¿Alguien puede explicar este extraño comportamiento de g ++?
C ++ interpreta el primero como la declaración de una función.
Como han dicho otros, x
es una declaración de función. Como no hay un insertador de ostream predefinido definido para los tipos de punteros de función, parece que g ++ usa la conversión bool implícita (utilizada para verificar si el puntero de una función es NULL) para encontrar una manera de generarla.
Visual C ++, por otro lado, se queja de que la función declarada x
nunca se define, y por lo tanto no puede completar el enlace. Sospecho que g ++ en este caso es lo suficientemente inteligente como para ver que la función nunca se llama, y por lo tanto no se preocupa por el enlace.
Puede intentar agregar una definición ficticia de la función int x(int(*)()) { return 0xdeadbeef; }
int x(int(*)()) { return 0xdeadbeef; }
al código y ver qué hace MSVC con él entonces.
Esta
int x(int());
Es en realidad una declaración de función. La entrada es una función de la siguiente firma.
int fn(void)
El puntero de función pasado a std::cout <<
se convierte en un bool (1) ya que es un puntero que no es NULL.
Para complementar la respuesta de GMan here ( x
es una definición de función) en cuanto a por qué el 1
.
La razón para que la salida sea 1
es que en el lugar de la llamada std::cout << x
, la función decae en un puntero a la función (el lenguaje no le permite pasar funciones como argumentos a otras funciones, por lo que con matrices se realiza una conversión implícita a puntero a ). Ahora, no hay una sobrecarga de un ostream
que tome un puntero de función, y el compilador intenta seleccionar una conversión a cualquiera de las sobrecargas disponibles. En ese punto, encuentra que la mejor secuencia de conversión es bool
e imprime 1
(el puntero no es 0).
Puede verificar esto cambiando el comportamiento, puede usar std::cout << std::boolalpha << x
, y se imprimirá true
lugar de 1
. Además, es interesante notar que VS tiene razón con este, ya que la expresión std::cout << x
requiere tomar la dirección de x
, luego se usa la función y el programa está mal formado si no hay una definición para esa funcion Puedes verificarlo nuevamente proporcionando una definición:
int f() {}
int main() {
int x(int()); // 1
x( &f ); // 2
}
int x( int(*)() ) { // 3
std::cout << "In x" << std::endl;
}
Donde he realizado manualmente la conversión de function
a pointer-to-function
en la definición de x
(1) y la llamada con el argumento f
(2) - tenga en cuenta que la declaración en 1 y la definición en 3 son la misma firma , y que el compilador ejecutará el &
in x( &f )
si no lo hace.
Simplemente añada más parens:
int main()
{
int x((int()));
int y = int();
cout << x << " " << y << endl;
}
Ahora x es un int, no una función.
int x(int());
Se analiza como declaración de función.
Declara una función llamada x
, que devuelve un int
y acepta un parámetro, que tiene el tipo de una función que devuelve un int
y no acepta argumentos.
Esto se conoce como el análisis más molesto.