2010-03-13 4 views
3

Disons que nous avons un entier non signé de 8 bits n (UINT8_MAX=255); Quel est le comportement du compilateur pour n=256? Où puis-je trouver une table de comportement par défaut lorsque la valeur d'un type de données est hors plage pour différents types de données? Y a-t-il une tendance à la façon dont ils se comportent lorsqu'ils sont hors de portée?Comportement avec les valeurs des types de données primitives 'out of range' et les macros PRI * C99

#include <stdio.h> 
#include <inttypes.h> 

uint8_t n = UINT8_MAX; 
int main() { 
    printf("%hhu ",n++); 
    printf("%hhu",n); 
    return 0; 
} 

avec gcc -std=c99 -Wall *.c Compiler, cette impression: 255 0

Aussi, est-il acceptable d'utiliser PRI de C99 * macros? Comment sont-ils nommés?

Répondre

6

n=256; convertit la valeur entière signée 256 en uint8_t, puis l'affecte à n. Cette conversion est définie par la norme pour prendre la valeur modulo-256, de sorte que n est définie sur 0.

Vous ne savez pas où vous pouvez trouver une table, mais les règles pour les conversions entières sont à 6.3.1.3:

1 Lorsqu'une valeur de type entier est converti en un autre type entier autre que _Bool, si la valeur peut être représentée par le nouveau type, elle est inchangée.

2 Dans le cas contraire, si le nouveau type est non signé, la valeur est convertie par de façon répétée en ajoutant ou en soustrayant une supérieure à la valeur maximale qui peut être représenté dans le nouveau type jusqu'à ce que la valeur est dans la plage de la nouvelle type.49)

3 dans le cas contraire, le nouveau type est signé et la valeur ne peut pas être représentée dans elle; soit le résultat est mise en œuvre défini ou un signal de mise en œuvre défini est élevé

Comme le souligne AndreyT dehors, cela ne couvre pas ce qui se passe lorsqu'un hors plage de valeurs se produit lors d'un calcul, comme opposé à lors d'une conversion. Pour les types non signés qui est couvert par 6.2.5/9:

Un calcul impliquant non signés opérandes ne peut jamais déborder, car un résultat qui ne peut pas être représenté par le type entier non signé résultant est réduit modulo le numéro est supérieur à la plus grande valeur que peut être représenté par le type résultant.

Pour les types signés, 3.4.3/3 dit:

Exemple Un exemple de comportement non défini est le comportement sur débordement d'entier.

(indirect, je sais, mais je suis trop paresseux pour continuer à chercher la description explicite quand c'est l'exemple canonique du comportement indéfini).

Notez également qu'en C, les règles de promotion d'entier sont assez compliquées. Les opérations arithmétiques sont toujours effectuées sur des opérandes du même type, donc si votre expression implique des types différents, il existe une liste de règles pour décider du type de l'opération. Les deux opérandes sont promus à ce type commun. C'est toujours au moins un int, cependant, pour un petit type comme uint8_t, l'arithmétique sera faite dans un int et reconverti en uint8_t lors de l'assignation au résultat. Par conséquent, par exemple:

uint8_t x = 100; 
uint8_t y = 100; 
unsigned int z = x * y; 

résultats à 10 000, pas 16 qui serait le résultat si z était un uint8_t aussi.

De même, est-il acceptable d'utiliser les macros PRI * C99? Comment sont-ils nommés?

Acceptable à qui? Cela ne me dérange pas, mais vous voudrez peut-être vérifier si votre compilateur les prend en charge ou non. GCC fait dans la première version que j'ai traîné, 3.4.4. Ils sont définis en 7.8.1. Si vous n'avez pas de copie de la norme C, utilisez ceci: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf. C'est un "brouillon" de la norme, publié quelques temps après la publication de la norme et incluant quelques corrections.

2

Le comportement est décrit dans la norme.

(*) Non signé Les types entiers implémentent l'arithmétique modulo. Le modulo est égal à 2^N où N est le nombre des bits formant la valeur dans le type. Cela signifie que les types non signés "enveloppent" sur débordement (aux deux extrémités). Si la valeur maximale du type est 255, alors 256 deviendra la valeur suivante après le retour à la ligne, qui est 0.

La seule exception à ce comportement pour les types non signés est lorsque vous convertissez une valeur en virgule flottante en unsigned type. En cas de débordement, le comportement n'est pas défini.

(*) Signé Les types entiers sont différents. Si le débordement se produit lors de la conversion à partir d'un type à virgule flottante, le comportement est indéfini (identique à celui des types non signés). Si le dépassement se produit pendant la conversion d'un autre type entier, le résultat est défini par l'implémentation. Si le débordement se produit pendant une opération arithmétique, le comportement n'est pas défini.

(*) Les types à virgule flottante provoquent un comportement indéfini en cas de dépassement pendant la conversion.

Questions connexes