Que sont les types littéraux entiers? Et comment ils sont stockés?

Je viens juste de commencer à apprendre le C et une question m’a énervé depuis un moment. Si j’écris

int i = -1; unsigned int j = 2; unsigned int k = -2; 

Quel est le type de littéral entier -1 et 2 et -2 , et comment est-il converti pour être stocké dans signed int et unsigned int ?

Qu’entend-on par entier signé, s’agit-il aussi de la propriété de variable ou de littéral entier? Comme -2 est un entier signé et 2 est un entier non signé?

Tout d’abord, -1 n’est pas une constante entière. C’est une expression consistant en un opérateur unaire appliqué à la constante 1 .

En C99 et C11, le type d’une constante entière décimale est le premier des entiers int , long int ou long long int dans lequel sa valeur tiendra. De même, un littéral octal ou hexadécimal a le type int , unsigned int , long int , unsigned long int , long long int ou unsigned long long int . Les détails sont dans N1570 6.4.4.1.

-1 et -2 sont des expressions constantes . Le résultat de l’opérateur unaire - a le même type que l’opérande (même si ce résultat provoque un débordement, comme le fait -INT_MIN dans la plupart des implémentations).

 int i = -1; 

La constante 1 et l’expression -1 sont toutes deux de type int . La valeur est stockée dans l’object int i ; aucune conversion n’est nécessaire. (Ssortingctement parlant, il est converti de int en int , mais cela n’a pas d’importance.)

 unsigned int j = 2; 

2 est de type int . Il est converti de int en unsigned int .

 unsigned int k = -2; 

-2 est de type int . Il est converti de int en unsigned int . Cette fois, parce que -2 est en dehors de la plage de unsigned int , la conversion est non sortingviale; le résultat est UINT_MAX - 1 .

Quelques terminologies:

Une constante est ce que certaines autres langues appellent un littéral . C’est un simple jeton qui représente une valeur constante. Les exemples sont 1 et 0xff .

Une expression constante est une expression devant être évaluée au moment de la compilation. Une constante est une expression constante. il en est de même pour une expression dont les opérandes sont des constantes ou des expressions constantes. Les exemples sont -1 et 2+2 .

En C99 et C11

Si vous voulez spécifier le type de votre entier, vous pouvez utiliser une constante entière :

Vous pouvez écrire un entier avec une représentation décimale, octale ou hexa:

 int decimal = 42; // nothing special int octal = 052; // 0 in front of the number int hexa = 0x2a; // 0x int HEXA = 0X2A; // 0X 

Représentation décimale:

Par défaut, le type -1, 0, 1, etc. est int , long int ou long long int . Le compilateur doit atteindre le type pouvant gérer votre valeur:

 int a = 1; // 1 is a int long int b = 1125899906842624; // 1125899906842624 is a long int 

Cela ne fonctionne que pour la valeur signed , si vous voulez une valeur unsigned , vous devez append u ou U:

 unsigned int a = 1u; unsigned long int b = 1125899906842624u; 

Si vous voulez long int ou long long int mais pas int , vous pouvez utiliser l ou L:

 long int a = 1125899906842624l; 

Vous pouvez combiner u et l:

 unsigned long int a = 1125899906842624ul; 

Enfin, si vous voulez seulement long long int , vous pouvez utiliser ll ou LL:

 unsigned long long int a = 1125899906842624ll; 

Et encore, vous pouvez combiner avec vous.

 unsigned long long int a = 1125899906842624ull; 

Représentation octale et hexadécimale:

Sans suffixe, un entier correspondra avec int , long int , long long int , unsigned int , unsigned long int et unsigned long long int .

 int a = 0xFFFF; long int b = -0xFFFFFFFFFFFFFF; unsigned long long int c = 0xFFFFFFFFFFFFFFFF; 

u ne diffère pas de la représentation décimale. l ou L et ll ou LL ajoutent un type de valeur non signé.


Ceci est similaire aux littéraux de chaîne .

Quel est le type de littéral entier -1 et 2 et -2, et comment est-il converti pour être stocké dans signé int et unsigned int?

L’parsingur / compilateur C, comme dit précédemment par chux, “comprend” votre littéral comme un entier signé – toujours. Ils sont ensuite convertis pour correspondre à la variable que vous avez affectée, qui peut être de type différent. Ce faisant, certains bits peuvent être perdus ou ils peuvent changer de signification (par exemple, assigner une valeur négative à un entier non signé). Certains compilateurs peuvent vous avertir d’un “littéral hors de scope”, d’autres compilateurs peuvent accepter (et tronquer) vos littéraux en silence.

Que voulez-vous dire par entier signé, est-ce que la propriété de variable ou de littéral entier aussi, comme -2 est un entier signé et 2 est un entier non signé?

C’est une propriété de la variable. En réalité, il s’agit d’un “type” – écrit sous la forme d’un identifiant “deux mots”.

Je dirais que cela dépend du compilateur et de l’architecture de la machine. Pour 8 bits = 1 byte , le tableau suivant récapitule les différents types d’entiers avec leurs tailles requirejses pour les int (signées) et unsigned int sur les ordinateurs 32 et 64 bits:

 +------+------+---------+-------+--------+-------------+-----------+ |Type |char |short int|int |long int|long long int|int pointer| +------+-------+--------+-------+--------+-------------+-----------+ |32-bit|8 bits|16 bits |32 bits|32 bits |64 bits |32 bits | +------+------+---------+-------+--------+-------------+-----------+ |64-bit|8 bits|16 bits |32 bits|64 bits |64 bits |64 bits | +------+------+---------+-------+--------+-------------+-----------+ 

Comme vous le savez peut-être, la plus grande différence entre int (signé) et unsigned int est que, dans (signé), le bit le plus significatif (MSB) est réservé au signe de l’entier et par conséquent:

  • un int (signé) ayant n bits peut avoir une valeur comprise entre -(2^(n-1)) et (2^(n-1))-1
  • un unsigned int ayant n bits peut avoir une valeur comprise entre 0 et (2^n)-1

Maintenant, nous pouvons calculer la plage (valeurs possibles) de différents types int (singés) comme suit:

 +------+---------+----------+----------+----------+-------------+-----------+ |Type |char |short int |int |long int |long long int|int pointer| +------+---------+----------+----------+----------+-------------+-----------+ |32-bit|-(2^7) to|-(2^15) to|-(2^31) to|-(2^31) to|-(2^63) to |-(2^31) to | | |+(2^7)-1 |+(2^15)-1 |+(2^31)-1 |+(2^31)-1 |+(2^63)-1 |+(2^31)-1 | +------+---------+----------+----------+----------+-------------+-----------+ |64-bit|-(2^7) to|-(2^15) to|-(2^31) to|-(2^63) to|-(2^63) to |-(2^63) to | | |+(2^7)-1 |+(2^15)-1 |+(2^31)-1 |+(2^63)-1 |+(2^63)-1 |+(2^63)-1 | +------+---------+----------+----------+----------+-------------+-----------+ 

De plus, nous pouvons calculer la plage (valeurs possibles) de différents types d’ unsigned int comme suit:

 +------+-------+----------+-------+--------+-------------+-----------+ |Type |char |short int|int |long int|long long int|int pointer| +------+-------+---------+--------+--------+-------------+-----------+ |32-bit|0 to |0 to |0 to |0 to |0 to |0 to | | |(2^8)-1|(2^16)-1 |(2^32)-1|(2^32)-1|(2^64)-1 |(2^32)-1 | +------+-------+---------+--------+--------+-------------+-----------+ |64-bit|0 to |0 to |0 to |0 to |0 to |0 to | | |(2^8)-1|(2^16)-1 |(2^32)-1|(2^64)-1|(2^64)-1 |(2^64)-1 | +------+-------+---------+--------+--------+-------------+-----------+ 

Enfin, pour voir comment et pourquoi nous stockons un long long int utilisant 8 octets (64 bits) sur une machine 32 bits, voir ce post .