web-dev-qa-db-fra.com

Pourquoi unsigned int 0xFFFFFFFF est égal à int -1?

En C ou C++, il est dit que le nombre maximal qu'un size_t (un type de données int non signé) peut contenir est le même que le cast -1 à ce type de données. par exemple, voir valeur non valide pour size_t

Pourquoi?

Je veux dire, (en parlant de 32 bits) AFAIK le bit le plus significatif détient le signe dans un type de données signé (c'est-à-dire le bit 0x80000000 pour former un nombre négatif). alors, 1 est 0x00000001. 0x7FFFFFFFF est le plus grand nombre positif qu'un type de données int puisse contenir.

Ensuite, AFAIK la représentation binaire de -1 int devrait être 0x80000001 (peut-être que je me trompe). pourquoi/comment cette valeur binaire est convertie en quelque chose de complètement différent (0xFFFFFFFF) lors du transtypage en non signé ?? ou .. comment est-il possible de former un -1 binaire à partir de 0xFFFFFFFF?

Je ne doute pas qu'en C: ((unsigned int) -1) == 0xFFFFFFFF ou ((int) 0xFFFFFFFF) == -1 est également vrai que 1 + 1 == 2, je me demande juste pourquoi.

26
conejoroy

C et C++ peuvent fonctionner sur de nombreuses architectures et types de machines différents. Par conséquent, ils peuvent avoir différentes représentations des nombres: le complément à deux et le complément à l'un étant le plus courant. En général, vous ne devez pas compter sur une représentation particulière dans votre programme.

Pour les types entiers non signés (size_t étant l'un d'entre eux), la norme C (et la norme C++ aussi, je pense) spécifie des règles de débordement précises. En bref, si SIZE_MAX est la valeur maximale du type size_t, puis l'expression

(size_t) (SIZE_MAX + 1)

est garanti d'être 0, et par conséquent, vous pouvez être sûr que (size_t) -1 est égal à SIZE_MAX. Il en va de même pour les autres types non signés.

Notez que ce qui précède est vrai:

  • pour tous les types non signés,
  • même si la machine sous-jacente ne représente pas les nombres en complément à deux . Dans ce cas, le compilateur doit s'assurer que l'identité est vraie.

De plus, ce qui précède signifie que vous ne pouvez pas vous fier à des représentations spécifiques pour les types signés .

Edit : Afin de répondre à certains des commentaires:

Disons que nous avons un extrait de code comme:

int i = -1;
long j = i;

Il y a une conversion de type dans l'affectation en j. En supposant que int et long ont des tailles différentes (la plupart [tous?] Des systèmes 64 bits), les modèles de bits aux emplacements de mémoire pour i et j vont être différents, car ils ont des tailles différentes. Le compilateur s'assure que les valeurs de i et j sont -1.

De même, lorsque nous faisons:

size_t s = (size_t) -1

Une conversion de type est en cours. Le -1 est de type int. Il a un motif binaire, mais cela n'est pas pertinent pour cet exemple, car lorsque la conversion en size_t a lieu en raison du cast, le compilateur traduira la valeur selon les règles du type (size_t dans ce cas). Ainsi, même si int et size_t ont des tailles différentes, la norme garantit que la valeur stockée dans s ci-dessus sera la valeur maximale que size_t peut prendre.

Si nous faisons:

long j = LONG_MAX;
int i = j;

Si LONG_MAX est supérieur à INT_MAX, la valeur dans i est définie par l'implémentation (C89, section 3.2.1.2).

47
Alok Singhal

C'est ce qu'on appelle le complément à deux. Pour faire un nombre négatif, inversez tous les bits puis ajoutez 1. Donc, pour convertir 1 en -1, inversez-le en 0xFFFFFFFE, puis ajoutez 1 pour faire 0xFFFFFFFF.

Quant à savoir pourquoi cela se fait de cette façon, Wikipedia dit:

Le système à complément à deux a l'avantage de ne pas nécessiter que les circuits d'addition et de soustraction examinent les signes des opérandes pour déterminer s'il faut ajouter ou soustraire. Cette propriété rend le système à la fois plus simple à mettre en œuvre et capable de gérer facilement une arithmétique de plus haute précision.

26
Mark Ransom

Votre première question, pourquoi (unsigned)-1 donne que la plus grande valeur non signée possible n'est liée qu'accidentellement au complément à deux. La raison pour laquelle -1 transtypé en un type non signé donne la plus grande valeur possible pour ce type est parce que la norme dit que les types non signés "suivent les lois du modulo arithmétique 2n où n est le nombre de bits dans la représentation de la valeur de cette taille particulière d'entier. "

Maintenant, pour le complément à 2, la représentation de la plus grande valeur non signée possible et -1 se trouve être la même - mais même si le matériel utilise une autre représentation (par exemple, complément à 1 ou signe/amplitude), la conversion de -1 en un type non signé doit produisent toujours la plus grande valeur possible pour ce type.

7
Jerry Coffin

complément à deux est très bien pour faire la soustraction comme l'addition :)

 11111110 (254 ou -2) 
 +00000001 (1) 
 --------- 
 11111111 (255 ou -1) 
 
 11111111 (255 ou -1) 
 +00000001 (1) 
 --------- 
 100000000 (0 + 256) 
3
pmg

C'est complément à deux encodage.

Le principal avantage est que vous obtenez le même encodage, que vous utilisiez un int non signé ou signé. Si vous soustrayez 1 de 0, l'entier s'enroule simplement. Par conséquent, 1 de moins de 0 correspond à 0xFFFFFFFF.

1
Goz