flag c++ gcc compiler-construction undefined-behavior initialization

c++ - flag - Diversión con variables sin inicializar y compilador(GCC)



gcc flags list (2)

Tengo curiosidad por saber por qué este cambio repentino en el comportamiento de bool no inicializado?

Desmonte el código y vea lo que hace el compilador.

Mi conjetura: como el valor ahora solo se usa localmente, el compilador lo optimiza completamente. Como el comportamiento no está definido de todos modos, el compilador puede asumir cualquier valor, por ejemplo, false . Esta es una optimización bastante obvia, ya que el valor de b es constante en lo que concierne al compilador, y toda la lógica del switch es redundante. Entonces, ¿por qué ponerlo en el ejecutable?

(El punto importante aquí es realmente que b solo se usa localmente en el segundo código, y que a su vez activará más optimizaciones incluso en código no optimizado. El primer código debe estar en línea antes de que el compilador pueda realizar tales optimizaciones, o el Las rutas de código deben ser rastreadas, lo que no es trivial).

La sección §3.9.1 / 6 de la norma C ++ dice:

Los valores de tipo bool son true o false .

Ahora considera este código,

void f(bool b) { switch(b) //since b is bool, it''s value can be either true or false! { case true: cout << "possible value - true"; break; case false: cout << "possible value - false"; break; default: cout << "impossible value"; } } int main() { bool b; //note : b is uninitialized f(b); return 0; }

Compilar F:/workplace>g++ test.cpp -pedantic

Correr. Salida:

valor imposible

¿Salida inesperada? Bueno, no realmente, como el Estándar lee en la nota al pie de la sección §3.9.1 / 6 que:

El uso de un valor bool en las formas descritas por esta Norma Internacional como "indefinido" , como al examinar el valor de un objeto automático sin inicializar , puede hacer que se comporte como si no fuera ni verdadero ni falso .

Así que no importa cuántas veces compile y ejecute este programa, obtengo el mismo resultado: impossible value . Sin embargo, si lo cambio un poco, quito la función f() de la imagen y escribo el bloque de switch en main() :

int main() { bool b; //note : b is uninitialized switch(b) //since b is bool, it''s value can be either true or false! { case true: cout << "possible value - true"; break; case false: cout << "possible value - false"; break; default: cout << "impossible value"; } return 0; }

Luego compilo y ejecuto este programa, no obtengo impossible value como resultado; No importa cuántas veces lo repita, nunca obtengo impossible value .

Tengo curiosidad por saber por qué este cambio repentino en el comportamiento de bool no inicializado?

Bueno, desde la perspectiva del lenguaje, está claro: el comportamiento no está definido. Lo comprendo. También entiendo que el compilador es libre de hacer cualquier cosa. Desde la perspectiva del compilador, sin embargo, esto me parece muy interesante. ¿Qué podría hacer el compilador (es decir, GCC) en cada caso y por qué?

Estoy usando: g++ (GCC) 4.5.0 - MinGW, on Windows 7 Basic, 64-bit OS .


Hoy mismo me encontré con una versión de este error. Ofrezco mi experiencia aquí en caso de que sea esclarecedor para alguien más.

Tenía un código que se reducía a

if(!(a == b && c.d())) { do_something(); }

El error que estaba persiguiendo era que do_something() estaba sucediendo, erróneamente. Sin embargo, a era definitivamente igual a b y cd() parecía, devolviéndose verdadero.

Cuando estaba rastreando esto, agregué temporalmente estas impresiones de prueba:

if( a == b && c.d() ) printf("yes/n"; else printf("no/n"); if(!(a == b && c.d())) printf("noo/n"; else printf("yess/n");

Para mi sorpresa, esto imprimió yes y noo , lo que confirmó tanto por do_something sucedía algo, como que estaba sucediendo algo muy extraño.

Resultó que el método d() era algo así como

bool whatever::d() { return _successful; }

Pero el _successful no fue inicializado. Cuando imprimí su valor, era 236, por lo que antes había dicho que " cd() era, al parecer, volvía verdadero".

No inspeccioné el código de ensamblaje, pero supongo que en algunas circunstancias, gcc estaba probando si era distinto de cero o no, pero en otras, solo estaba probando el bit de orden inferior.

La inicialización correcta del _successful hizo que el error desapareciera. (Había estado sin inicializar durante diez años , desde que un programador anterior escribió el método d() . Sin embargo, el error no se había manifestado hasta hace unos meses. Esta es la razón por la que, a veces, el software es difícil).