2012-01-19 37 views
5

encontré un error en algún código c que escribí, y si bien fue relativamente fácil de corregir, quiero ser capaz de comprender mejor el problema subyacente. esencialmente, lo que sucedió es que tenía dos enteros sin signo (uint32_t, de hecho) que, cuando se aplicaba la operación del módulo, producía el equivalente sin signo de un número negativo, un número que se había envuelto y que por lo tanto era "grande". aquí es un programa de ejemplo para demostrar:desbordamiento sin signo con operador de módulo en C

#include <stdio.h> 
#include <stdint.h> 

int main(int argc, char* argv[]) { 

    uint32_t foo = -1; 
    uint32_t u = 2048; 
    uint64_t ul = 2048; 

    fprintf(stderr, "%d\n", foo); 
    fprintf(stderr, "%u\n", foo); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%ld\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % ul)); 
    fprintf(stderr, "%lu\n", foo % ul); 

    return 0; 

} 

esto produce la siguiente salida, en mi máquina x86_64:

-1 
4294967295 
18446744073709551104 
-512 
1536 
2047 

1536 es el número que estaba esperando, pero (uint32_t) (- 512) es el número que obtenía, que, como se puede imaginar, arrojó un poco las cosas.

lo tanto, supongo que mi pregunta es la siguiente: ¿por qué una operación módulo entre dos números sin signo, en este caso, producir un número que es mayor que el divisor (es decir, un número negativo)? ¿Hay alguna razón por la cual se prefiere este comportamiento?

+1

2600000000 es un int (o tal vez un int de 64 bits, largo o largo), que puede haber causado que el resultado de la multiplicación se convierta en un (firmado) de largo. ¿En qué plataforma estás? – Random832

Respuesta

3

Creo que la razón es que el compilador es la interpretación literal del 2600000000 como un número de 64 bits con signo, ya que no cabe en un int de 32 bits con signo. Si reemplaza el número con 2600000000U, debe obtener el resultado que espera.

+2

En realidad OP invocó UB pasando las cadenas de formato incorrecto a 'printf'. –

2

No tengo una referencia a la mano, pero estoy bastante seguro de que cuando haces esa multiplicación, los promueve a int64_t, porque necesita forzar los dos multiplicandos a un tipo integral con signo. Trato 2600000000u en lugar de 2600000000 ....

Cuestiones relacionadas