Quel est le problème avec cette int pour la conversion flottante en C?

Je suis dérouté par la sortie du bit de code suivant:

float a = 1.32; int* b; b= &a; printf("%d", *b); 

Ce peu de code transforme le float en int, mais le résultat obtenu est le suivant: 1068037571

Est-ce lié aux capacités de conversion IEEE 754 de l’ordinateur? Merci!

Votre programme appelle un comportement indéfini. Vous êtes simplement en train de réinterpréter la représentation du float en tant int . Vous ne convertissez pas catégoriquement un int en un float . Vous ne pouvez pas vous attendre à un comportement particulier.

Pour convertir le float en int, utilisez le code suivant:

 int b = a; 

qui tronque le float à un int .

Ce que vous faites avec votre code, c’est jeter un coup d’œil à la façon dont le nombre à virgule flottante est stocké. Une virgule flottante occupe 4 octets en mémoire (généralement), comme suit (exemple tiré de wikipedia):

entrez la description de l'image ici

Lorsque vous exécutez votre code, vous prétendez que ces bits sont un entier de quatre octets:

 float a = 1.32; int* b; b= &a; printf("%d", *b); 

Si vous voulez voir la représentation hexadécimale, faites juste

 printf("%08x", *b); 

Et vous aurez

 3f9d70a4 

ce qui signifie que le motif de bits était

 00111111100111010111000010100100 

Le briser:

 0 01111111 00111010111000010100100 

bit de signe 0 exposant fraction 01111111 (1)00111010111000010100100

Et vous trouverez ce nombre binary

 100111010111000010100100 = 10317988 

Et cela

 10317988.0 / (4096.0*2048.0) = 1.23 

UPDATE Programme complet qui montre exactement comment faire cela:

 #include  #include  #include  int main(void) { float a = 1.23; uint32_t *b = (uint32_t *)&a; uint32_t signbit; uint32_t exponent; uint32_t mantissa; uint32_t fpAsInt; fpAsInt = *b; signbit = (fpAsInt & 0x80000000) >> 31; exponent = (fpAsInt & 0x7F800000) >> 23 ; mantissa = (fpAsInt & 0x007FFFFF) | 0x00800000; printf("fpAsInt: 0x%08x\n", fpAsInt); printf("sign bit: %d\n", signbit); printf("exponent: 0x%02x\n", exponent); printf("mantissa: 0x%03x\n", mantissa); printf("the value is %10f\n", ((signbit == 1)?-1.0:1.0)*mantissa / pow(2.0, (127 - exponent + 23))); printf("the original value was %10f\n", a); } 

Imprime le résultat

 fpAsInt: 0x3f9d70a4 sign bit: 0 exponent: 0x7f mantissa: 0x9d70a4 the value is 1.2300000191 the original value is 1.2300000191 

Cela peut sembler être une sortingcherie que d’utiliser des calculs en virgule flottante à la dernière ligne (critique valable), mais le but ici est de montrer comment le virgule flottante est construit, et non pas comment utiliser des calculs entiers pour extraire la valeur.

Remarque – Je suppose que le nombre à virgule flottante est la représentation en octets IEEE 4. De plus, j’ai inclus un casting spécifique pour se débarrasser des avertissements du compilateur. Ne le faites que lorsque vous êtes sûr de savoir ce que vous faites …

UN PLUS D’EDIT

Il a été souligné que le code est toujours soumis à un comportement indéfini. Pour tenter de contourner ce problème et de vous donner un aperçu de ce qui précède, faisons cela une fois de plus. Maintenant, j’utilise l’union d’un tableau de bits et d’un float pour accéder “légalement” aux différents éléments – et je ne reçois aucun avertissement lors de la compilation avec -Wall -pedantic . Cela peut ne pas suffire, mais c’est le meilleur que je connaisse …

 #include  #include  #include  union ieee754_float { float f; /* This is the IEEE 754 single-precision format on a little-endian machine. */ struct { unsigned int mantissa:23; unsigned int exponent:8; unsigned int negative:1; } ieee; }; int main(void) { float a = 1.23; union ieee754_float *pa; pa = (union ieee754_float*)&a; uint32_t signbit; uint32_t exponent; uint32_t mantissa; signbit = pa->ieee.negative; exponent = pa->ieee.exponent; mantissa = pa->ieee.mantissa | 0x00800000; printf("sign bit: %d\n", signbit); printf("exponent: 0x%02x\n", exponent); printf("mantissa: 0x%03x\n", mantissa); printf("the value is %.10f\n", ((signbit == 1)?-1.0:1.0)*mantissa / pow(2.0, (127 - exponent + 23))); printf("the original value is %.10f\n", a); } 

Il est possible de répondre à de nombreuses questions de la balise C sur StackOverflow en revenant à ces règles de base:

  • & prend une variable et produit un pointeur
  • * prend un pointeur et produit une variable

Alors vous avez dit “prenez cette variable float et faites-moi un pointeur. Maintenant, prenez ce pointeur et faites-moi une variable int.” Vous n’avez jamais dit “prenez cette valeur float et faites-moi une valeur int”. Vous avez dit “prenez un pointeur qui peut être transformé en une variable float et transformez-le en une variable int à la place”. Qu’est-ce qui se passe quand tu fais ça? C’est entièrement au compilateur de décider.