c - tipos - unsigned int para que sirve
Desbordamiento aparece incluso cuando se usa int largo sin firmar (5)
El desbordamiento se produce antes de que se asigne un valor a la variable. Para evitar ese uso sufijo largo y largo:
60123456LL * 128 * sizeof(double)
(los comentarios también sugieren ULL, que no es necesario aquí porque los valores están dentro del rango firmado, pero esa sería la forma genérica de hacerlo)
Cuando hago el siguiente cálculo:
unsigned long long int data_size = 60123456 * 128 * sizeof(double);
printf("data_size= %llu /n", data_size);
Sorprendentemente recibo advertencia de desbordamiento:
test.c:20:49: warning: overflow in expression; result is -894132224 with type ''int'' [-Winteger-overflow]
unsigned long long int data_size = 60123456 * 128 * sizeof(double);
^
1 warning generated.
¡No puedo entender por qué aparece este error aunque estoy usando unsigned long long int
! ¿Alguien puede explicar por qué? Gracias
El lexer 5.1.1.2 Translation phases
tipos en constantes durante la fase de traducción 7 (conversión de tokens de preprocesamiento en tokens C). Cf 5.1.1.2 Translation phases
5.1.1.2 5.1.1.2 Translation phases
. Como dijeron los demás, el lexer adjuntará a sus constantes el tipo int
lugar de unsigned long long
que desee, y para que las default arithmetic conversions
generen una constante de tipo unsigned long long
en el lado derecho de la tarea que necesita para decirle al lexer que agregue el tipo unsigned long long
por lo menos en una constante de la operación *
que genera el desbordamiento, por lo tanto, escriba 60123456ULL * 128
o 60123456 * 128ULL
o ambos.
Estás convirtiendo a "largo" demasiado tarde. 60123456 * 128
sigue siendo una expresión int que desborda.
Intente 60123456LL * 128
lugar. (LL porque no se garantiza que el valor resultante se ajuste a un largo).
Las constantes 60123456
y 128
son de tipo int
, por lo tanto, la expresión 60123456 * 128
también es de tipo int
. El valor de esta expresión desbordaría el rango de un int
. El compilador es capaz de detectarlo en este caso porque ambos operandos son constantes.
Debe usar el sufijo ULL
en el primer operando para hacer que el tipo de constante unsigned long long
. De esa manera coincide con el tipo al que está asignado. Luego, para cualquier operación que involucre este valor, el otro operando será promovido a unsigned long long
antes de que se aplique la operación y no tendrá ningún desbordamiento.
Entonces la expresión resultante debería verse así:
unsigned long long int data_size = 60123456ULL * 128 * sizeof(double);
unsigned long long int data_size = 60123456 * 128 * sizeof(double); // trouble-some code
El tipo de destino unsigned long long int data_size =
no es relevante para el cálculo del producto 60123456 * 128 * sizeof(double)
.
Lo mejor para asegurar que las matemáticas se realicen utilizando al menos el tamaño del tipo de destino para evitar el desbordamiento. En el caso de OP, eso implica una constante con LLU
.
Hay 2 cálculos de productos, cada uno con su propio tipo matemático.
60123456
es un int
o long
dependiendo del rango int
. Supongamos que es un int
.
60123456 * 128
es un int * int
. El producto matemático 7695802368
excede el rango de entero con signo de 32 bits, por lo tanto, desbordamiento de entero con signo o comportamiento indefinido (UB) con un int
32 bits.
Si 60123456 * 128
no se desbordara, dice int
64 bits, entonces la siguiente multiplicación sería * sizeof(double);
y así int * size_t
da como resultado un producto de tipo size_t
.
El cálculo del producto debe utilizar, al menos, cálculos matemáticos unsigned long long
como se muestra a continuación:
unsigned long long int data_size = 1LLU * 60123456 * 128 * sizeof(double);
// or
unsigned long long int data_size = 60123456LLU * 128 * sizeof(double);
// or
unsigned long long int data_size = 60123456;
data_size *= 128 * sizeof(double);
// or avoiding naked magic numbers
#define A_HEIGHT 60123456
#define A_WIDTH 128
unsigned long long int data_size = 1LLU * A_HEIGHT * A_WIDTH * sizeof(double);
El tamaño de sizeof (double)
insinúa que el código está intentando encontrar el tamaño de alguna estructura similar a 2D. Yo esperaría un código como el siguiente. Observe que el tipo de resultado de sizeof
es size_t
, por lo que la matemática del producto se realiza utilizando al menos size_t
math.
size_t data_size = sizeof(double) * 60123456 * 128;
printf("data_size= %zu/n", data_size);
Consulte también ¿Por qué escribir 1,000,000,000 como 1000 * 1000 * 1000 en C? y mi respuesta es una razón para no usar 1000 * 1000 * 1000 para detalles aplicables.