29 votes

Le débordement apparaît même lors de l'utilisation d'un entier long non signé

Quand je fais le calcul suivant:

 unsigned long long int data_size = 60123456 * 128 * sizeof(double);
printf("data_size= %llu  \n", data_size);
 

Je reçois étonnamment un avertissement de débordement:

 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.
 

Je ne comprends pas pourquoi cette erreur apparaît même si j'utilise unsigned long long int ! Quelqu'un peut-il expliquer pourquoi? Je vous remercie

46voto

Jean-François Fabre Points 94672

Un débordement se produit avant que la valeur ne soit affectée à la variable. Pour éviter cela, utilisez un long suffixe long:

 60123456LL * 128 * sizeof(double)
 

(Les commentaires suggèrent également ULL qui n'est pas nécessaire ici parce que les valeurs sont dans la plage signée, mais ce serait la voie générique à suivre)

18voto

glglgl Points 35668

Vous vous convertissez en «long long» trop tard. 60123456 * 128 est toujours une expression int débordante.

Essayez plutôt 60123456LL * 128 . (LL car la valeur résultante n'est pas garantie de tenir dans une longue.)

12voto

chux Points 13185
unsigned long long int data_size = 60123456 * 128 * sizeof(double);  // trouble-some code

Le type de destination unsigned long long int data_size = n'est pas pertinent pour le produit de calcul 60123456 * 128 * sizeof(double).

Meilleur pour assurer des mathématiques se fait à l'aide d'au moins la taille de la cible type d'éviter les débordements. Dans l'OP, ça implique une constante avec LLU.


Il y a 2 produits de calculs, chacun avec leur propre type de mathématiques.

60123456 est int ou long selon int de la gamme. Nous supposons que c'est un int.

60123456 * 128 est int * int. Le calcul de produit 7695802368 dépasse 32 bits entier signé de gamme, donc signé débordement d'entier ou un comportement indéfini (UB) avec un 32 bits int.

Si 60123456 * 128 n'a pas de débordement, dit-64-bit int, plus de la prochaine multiplication serait * sizeof(double); et ainsi de int * size_t résultats en size_t type de produit.

Produit de calcul doit utiliser au moins unsigned long long mathématiques comme ci-dessous:

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);

L' sizeof (double) conseils de ce code est d'essayer de trouver la taille de certaines 2D-forme de la structure. Je m'attends à un code comme suit. Notez le type de résultat de l' sizeof est size_t, de sorte que le produit de mathématiques se fait à l'aide d'au moins size_t en mathématiques.

size_t data_size = sizeof(double) * 60123456 * 128;
printf("data_size= %zu\n", data_size);

Voir aussi Pourquoi écrire que 1 000 000 000 d'1000*1000*1000 en C? et ma réponse raisons de ne pas utiliser 1000 * 1000 * 1000 pour les détails..

3voto

dbush Points 8590

Les constantes 60123456 et 128 sont de type int, donc l'expression 60123456 * 128 est également de type int. La valeur de cette expression serait de dépassement de la plage d'un int. Le compilateur est capable de le détecter dans ce cas, parce que les deux opérandes sont des constantes.

Vous devez utiliser l' ULL suffixe sur le premier opérande de faire le type de la constante unsigned long long. De cette façon, il correspond au type d'être affectés. Alors pour toute opération impliquant cette valeur, l'autre opérande sera promu unsigned long long avant l'opération est appliquée et que vous n'aurez pas de débordement.

Donc, l'expression qui en résulte devrait ressembler à ceci:

unsigned long long int data_size = 60123456ULL * 128 * sizeof(double);

3voto

alinsoar Points 3583

L'analyseur lexical attache types de constantes lors de la traduction de la phase 7 (conversion de prétraitement des jetons en C jetons.) cf ISO9899 5.1.1.2 Translation phases. Comme les autres ont dit, l'analyseur lexical, vous fixez sur votre constantes du type int au lieu de unsigned long long comme vous le souhaitez, et pour que l' default arithmetic conversions pour générer une constante de type unsigned long long sur le côté droit de la mission que vous avez à dire à l'analyseur lexical pour fixer le type unsigned long long sur au moins une constante de l'exploitation, * qui génère le dépassement, par écrit, 60123456ULL * 128 ou 60123456 * 128ULL , ou les deux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X