C Language Desbordamiento de entero firmado


Ejemplo

Según el párrafo 6.5 / 5 de C99 y C11, la evaluación de una expresión produce un comportamiento indefinido si el resultado no es un valor representable del tipo de expresión. Para los tipos aritméticos, eso se llama un desbordamiento . La aritmética de enteros sin signo no se desborda porque se aplica el párrafo 6.2.5 / 9, lo que ocasiona que cualquier resultado sin firmar que de otra forma esté fuera de rango se reduzca a un valor dentro del rango. No hay ninguna disposición análoga para los tipos de enteros con signo, sin embargo; Estos pueden y se desbordan, produciendo un comportamiento indefinido. Por ejemplo,

#include <limits.h>      /* to get INT_MAX */

int main(void) {
    int i = INT_MAX + 1; /* Overflow happens here */
    return 0;
}

La mayoría de los casos de este tipo de comportamiento indefinido son más difíciles de reconocer o predecir. En principio, el desbordamiento puede surgir de cualquier operación de suma, resta o multiplicación en enteros con signo (sujeto a las conversiones aritméticas habituales) donde no existen límites efectivos o una relación entre los operandos para evitarlo. Por ejemplo, esta función:

int square(int x) {
    return x * x;  /* overflows for some values of x */
}

es razonable, y hace lo correcto para valores de argumento suficientemente pequeños, pero su comportamiento no está definido para valores de argumento más grandes. No se puede juzgar solo por la función si los programas que lo llaman exhiben un comportamiento indefinido como resultado. Depende de qué argumentos le pasen.

Por otro lado, considere este ejemplo trivial de aritmética de enteros con signo de desbordamiento seguro:

int zero(int x) {
    return x - x;  /* Cannot overflow */
}

La relación entre los operandos del operador de resta asegura que la resta nunca se desborda. O considere este ejemplo algo más práctico:

int sizeDelta(FILE *f1, FILE *f2) {
    int count1 = 0;
    int count2 = 0;
    while (fgetc(f1) != EOF) count1++;  /* might overflow */
    while (fgetc(f2) != EOF) count2++;  /* might overflow */

    return count1 - count2; /* provided no UB to this point, will not overflow */
}

Mientras los contadores no se desborden individualmente, los operandos de la resta final serán ambos no negativos. Todas las diferencias entre cualquiera de estos dos valores se pueden representar como int .