2012-01-28 21 views
8

He realizado algunas investigaciones sobre Stackoverflow sobre reverse para bucles en C++ que usan un entero sin signo en lugar de uno firmado. Pero aún NO entiendo por qué hay un problema (vea Unsigned int reverse iteration with for loops). ¿Por qué el siguiente código producirá un error de segmentación?enteros sin signo en C++ para bucles

#include <vector> 
#include <iostream> 
using namespace std; 

int main(void) 
{ 
    vector<double> x(10); 

    for (unsigned int i = 9; i >= 0; i--) 
    { 
     cout << "i= " << i << endl; 
     x[i] = 1.0; 
    } 

    cout << "x0= " << x[0] << endl; 

    return 0; 
} 

entiendo que el problema es cuando el índice i será igual a cero, ya que es algo así como un desbordamiento. Pero creo que un entero sin signo puede tomar el valor cero, ¿no? Ahora si lo reemplazo con un entero con signo, no hay absolutamente ningún problema.

¿Alguien me puede explicar el mecanismo detrás de ese lazo inverso con un entero sin signo?

Muchas gracias!

+3

'i> = 0' siempre es verdadero para' i' sin signo, por lo que el ciclo nunca termina. – TonyK

+0

Lea las advertencias del compilador, son útiles. En este caso, su compilador probablemente debería haberle advertido sobre el hecho de que la condición en su ciclo siempre es verdadera. – dragonroot

+0

@dragonroot: Desafortunadamente no. Yo uso la bandera de -Wall de g ++. ¿Conoces una bandera del compilador que detectará este tipo de problema? Gracias. – Benjamin

Respuesta

24

El problema aquí es que un entero sin signo nunca es negativo.

Por lo tanto, el bucle de prueba:

i >= 0 

siempre habrá cierto. Así obtienes un ciclo infinito.

Cuando cae por debajo de cero, se ajusta al valor más alto unsigned valor.
Por lo tanto, también accederá a x[i] fuera de límites.

Esto no es un problema para enteros con signo porque simplemente irá negativo y por lo tanto fallará i >= 0.

Por lo tanto, si desea utilizar enteros sin signo, puede intentar una de las siguientes posibilidades:

for (unsigned int i = 9; i-- != 0;) 

y

for (unsigned int i = 9; i != -1; i--) 

Estos dos fueron sugeridos por GManNickG y AndreyT de los comentarios.


Y aquí está mi original 3 versiones:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--) 

o

for (unsigned int i = 9; i != ~(unsigned)0; i--) 

o

for (unsigned int i = 9; i != UINT_MAX; i--) 
+0

O tiene 'i' be * one more * que el índice, por lo que' 0' es una condición de terminación adecuada. Tan complicado como el resto sin embargo. –

+0

¿No es un comportamiento indefinido de desbordamiento de enteros y subdesbordamiento? – josefx

+2

@josefx Solo el entero con signo de exceso/defecto es un comportamiento indefinido. – Mysticial

4

Cualquiera que sea el valor de unsigned int i siempre es cierto que i >= 0 de manera que y nuestro bucle for nunca termina.

En otras palabras, si en algún momento i es 0 y que disminuirlo, que aún se mantiene no negativo, ya que contiene entonces un número enorme, probablemente 4294967295 (es decir 2 -1).

6

El problema es que su bucle permite que yo sea tan bajo como cero y solo espera salir del bucle si soy menor que 0. Como i no está firmado, nunca puede ser menor que 0. Pasa a 2^32-1.Eso es mayor que el tamaño de su vector y por lo tanto da como resultado una segfault.

3

El problema es aquí:

for (unsigned int i = 9; i >= 0; i--) 

Usted está comenzando con un valor de 9 para un int sin signo y su definición es la salida i> = 0 y esto será siempre verdad. (unsigned int nunca será negativo !!!). Debido a esto, su bucle comenzará de nuevo (bucle infinito, porque i = 0, luego -1 va máx uint).

Cuestiones relacionadas