c++ gcc gcc-warning

c++ - No entienda la advertencia de "asumir un desbordamiento firmado"



gcc gcc-warning (5)

Creo que el compilador cambió.

positionIndex[i]++; if ( positionIndex[i] < endIndex[i] )

en algo más optimizado como

if ( positionIndex[i]++ < endIndex[i] )

asi que

if ( positionIndex[i] + 1 < endIndex[i] )

que causa un comportamiento indefinido en caso de desbordamiento (gracias Seth).

Estoy obteniendo:

advertencia: suponiendo que el desbordamiento firmado no se produce cuando se asume que (X + c) <X siempre es falso [-desbordamiento de restricciones]

en esta linea:

if ( this->m_PositionIndex[in] < this->m_EndIndex[in] )

m_PositionIndex y m_EndIndex de tipo itk::Index ( http://www.itk.org/Doxygen/html/classitk_1_1Index.html ), y su operator[] devuelve un itk::Index signed long .

(es la línea 37 aquí: https://github.com/Kitware/ITK/blob/master/Modules/Core/Common/include/itkImageRegionConstIteratorWithIndex.hxx para el contexto)

¿Alguien puede explicar qué causaría esa advertencia aquí? No veo el patrón (x+c) < x ninguna parte, ya que es simplemente una comparación signed long .

Intenté reproducirlo en un ejemplo autocontenido:

#include <iostream> namespace itk { struct Index { signed long data[2]; Index() { data[0] = 0; data[1] = 0; } signed long& operator[](unsigned int i) { return data[i]; } }; } int main (int argc, char *argv[]) { itk::Index positionIndex; itk::Index endIndex; for(unsigned int i = 0; i < 2; i++) { positionIndex[i]++; if ( positionIndex[i] < endIndex[i] ) { std::cout << "something" << std::endl; } } return 0; }

Pero no recibo la advertencia allí. ¿Alguna idea sobre qué es diferente entre mi demo y el código real, o qué podría estar causando la advertencia en el código real? Recibo la advertencia con gcc 4.7.0 y 4.7.2 con la marca -Wall.


El compilador le está diciendo que tiene suficiente conocimiento estático de ese fragmento para saber que la prueba siempre tendrá éxito si puede optimizar la prueba suponiendo que no se desbordará ninguna operación firmada.

En otras palabras, la única forma en que x + 1 < x volverá a ser verdadero cuando x esté firmado es si x ya tiene el valor firmado máximo. [-Wstrict-overflow] avise al compilador cuando puede asumir que no se desbordará ninguna adición firmada; Básicamente le está diciendo que optimizará la prueba porque el desbordamiento firmado es un comportamiento indefinido.

Si desea suprimir la advertencia, deshágase de la prueba.


En mi caso, esta fue una buena advertencia del compilador. Tuve un error de copiar / pegar estúpido en el que tenía un bucle dentro de un bucle, y cada uno tenía el mismo conjunto de condiciones. Algo como esto:

for (index = 0; index < someLoopLimit; index++) { // blah, blah, blah..... for (index = 0; index < someLoopLimit; index++) { // More blah, blah, blah.... } }

Esta advertencia me ahorró tiempo de depuración. Gracias, gcc !!!


Esto es casi seguro que es un error, aunque no puedo decir cuál de los tres errores posibles es.

Creo que gcc de alguna manera está calculando a partir de qué se calculan los valores en ''this-> m_PositionIndex [in]'', es decir, que ambos valores se derivan del mismo valor, uno con un desplazamiento que también puede resultar positivo . En consecuencia, se deduce que una rama de la construcción if / else es un código inalcanzable.

Esto es malo. Seguro. ¿Por qué? Bueno, hay exactamente tres posibilidades:

  1. gcc tiene razón en que el código es inalcanzable, y usted pasó por alto que este es el caso. En este caso simplemente tienes código inflado. Lo mejor de las tres posibilidades, pero sigue siendo malo en términos de calidad de código.

  2. gcc tiene razón en que el código es inalcanzable, pero querías que fuera accesible. En este caso, debe echar un segundo vistazo a por qué no se puede acceder y corregir el error en su lógica.

  3. gcc está equivocado, has tropezado con un error en él. Bastante improbable, pero posible, y desafortunadamente muy difícil de probar.

Lo realmente malo es que es absolutamente necesario descubrir exactamente por qué no se puede acceder al código, o si se debe refutar que gcc es correcto (lo que es más fácil decirlo que hacerlo). De acuerdo con la ley de Murphy, asumir el caso 1. o 3. sin probar que se asegurará de que sea el caso 2., y que tendrá que buscar el error por segunda vez ...


Para simplemente deshabilitar esta advertencia, use -Wno-strict-overflow . Para desactivar la optimización específica que activa esta advertencia, utilice -fno-strict-overflow o -fwrapv .

La página de manual de gcc describe que esta advertencia se puede controlar con niveles: -Wstrict-overflow=n .

Si esto detiene su compilación debido a -Werror , puede -Werror sin ocultar las advertencias utilizando -Wno-error=strict-overflow (o simplemente -Wno-error para anular -Werror ).

Análisis y comentario ...

Recibí la misma advertencia y pasé un par de horas intentando reproducirla en un ejemplo más pequeño, pero nunca lo logré. Mi código real implicaba llamar a una función en línea en una clase con plantilla, pero el algoritmo se simplifica a lo siguiente ...

int X = some_unpredictable_value_well_within_the_range_of_int(); for ( int c=0; c<4; c++ ) assert( X+c >= X ); ## true unless (X+c) overflows

En mi caso, la advertencia estaba correlacionada de alguna manera con el optimizador que desenrollaba el bucle for , por lo que pude solucionarlo al declarar volatile int c=0 . Otra cosa que lo solucionó fue declarar unsigned int c=0 , pero no estoy exactamente seguro de por qué eso hace una diferencia. Otra cosa que lo solucionó fue hacer que el bucle contara lo suficientemente grande como para que el bucle no se desenrollara, pero esa no es una solución útil.

Entonces, ¿qué está diciendo realmente esta advertencia? O bien está diciendo que el optimizador ha modificado la semántica de su algoritmo (suponiendo que no hay desbordamiento), o simplemente le informa que el optimizador está asumiendo que su código no tiene el comportamiento indefinido de desbordar un entero con signo . A menos que los enteros con signo desbordados formen parte del comportamiento previsto de su programa, este mensaje probablemente no indique un problema en su código, por lo que es probable que desee desactivarlo para las compilaciones normales. Si recibe esta advertencia pero no está seguro acerca del código en cuestión, puede ser más seguro simplemente desactivar la optimización con -fwrapv .

Por cierto, me encontré con este problema en GCC 4.7, pero el mismo código compilado sin previo aviso con 4.8, tal vez indica que los desarrolladores de GCC reconocieron la necesidad de ser un poco menos "estricto" en el caso normal (o tal vez fue solo por diferencias en el optimizador).

Filosofía...

En [C ++ 11: N3242 $ 5.0.4], indica ...

Si durante la evaluación de una expresión, el resultado no está definido matemáticamente o no está en el rango de valores representables para su tipo, el comportamiento no está definido.

Esto significa que un compilador conforme puede simplemente asumir que el desbordamiento nunca ocurre (incluso para tipos sin firma).

En C ++, debido a características tales como plantillas y constructores de copias, la elision de operaciones sin sentido es una importante capacidad de optimización. A veces, sin embargo, si está utilizando C ++ como un "lenguaje de sistema" de bajo nivel, es probable que solo desee que el compilador haga lo que le dice que haga, y confíe en el comportamiento del hardware subyacente. Dado el lenguaje del estándar, no estoy seguro de cómo lograrlo de una manera independiente del compilador.