Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un charmant problème de conversion

23 réponses
Avatar
rixed
Petit exercice amusant :
comprendre pourquoi ce programme n'affiche pas deux fois la même valeur.

#include <stdio.h>
int main(void)
{
unsigned int a = 3232235530U;
float value = a;
printf("a=%.2f %.2f\n", (float)a, value);
return 0;
}


Ca nous a bien occupé une demi heure aujourd'hui, j'espère que ça vous
amusera autant que nous.

3 réponses

1 2 3
Avatar
Pierre Maurette
, le 13/09/2009 a écrit :

[...]

Qu'en pensez vous ?



J'en pense comme vous qu'il y a certainement une erreur, et je ne pense
pas qu'il s'agisse d'un bug en ce sens que cette erreur est
certainement assumée et connue des habitués. Mais je n'ai pas trop
envie de me jeter dans la norme ni dans les documentations de gcc ni de
msvc, surtout à l'heure de la messe ou du petit blanc du dimanche
matin.

J'ai testé avec Visual Studio Express. En 32bit, j'obtiens (j'ajoute
des sizeof, à toutes fins utiles):

sizeof int = 4
sizeof void* = 4
sizeof float = 4
sizeof double = 8
sizeof long double = 8
a232235530.00 3232235520.00

Et le code machine:

unsigned int a = 3232235530U;
00401006 mov dword ptr [a],0C0A8000Ah
float value = (float)a;
0040100D mov eax,dword ptr [a]
00401010 mov dword ptr [ebp-10h],eax
00401013 mov dword ptr [ebp-0Ch],0
0040101A fild qword ptr [ebp-10h]
0040101D fstp dword ptr [value]
printf("a=%.2f %.2fn", (float)a, value);
00401020 fld dword ptr [value]
00401023 sub esp,8
00401026 fstp qword ptr [esp]
00401029 mov ecx,dword ptr [a]
0040102C mov dword ptr [ebp-18h],ecx
0040102F mov dword ptr [ebp-14h],0
00401036 fild qword ptr [ebp-18h]
00401039 sub esp,8
0040103C fstp qword ptr [esp]
0040103F push offset ___native_dllmain_reason-10h (403000h)
00401044 call dword ptr [__imp__printf (4020A0h)]
0040104A add esp,14h

Il est clair que le cast (float) dans le printf() est zappé. Ce ne
serait pas immédiat, mais pas la mer à boire quand même. On voit
également en germe un autre souci potentiel, c'est que les calculs sur
des float sans autre précaution risquent d'être menés au moins en
partie sur des double, en fait des extended. Il me semble que c'est
documenté abondamment.

Maintenant en 64bit (le compilateur est différent):

sizeof int = 4
sizeof void* = 8
sizeof float = 4
sizeof double = 8
sizeof long double = 8
a232235520.00 3232235520.00

unsigned int a = 3232235530U;
0000000140001004 mov dword ptr [a],0C0A8000Ah
float value = (float)a;
000000014000100C mov eax,dword ptr [a]
0000000140001010 pxor xmm0,xmm0
0000000140001014 cvtsi2ss xmm0,rax
0000000140001019 movss dword ptr [value],xmm0
printf("a=%.2f %.2fn", (float)a, value);
000000014000101F movd xmm2,dword ptr [value]
0000000140001025 cvtps2pd xmm2,xmm2
0000000140001028 mov eax,dword ptr [a]
000000014000102C pxor xmm0,xmm0
0000000140001030 cvtsi2ss xmm0,rax
0000000140001035 unpcklps xmm0,xmm0
0000000140001038 cvtps2pd xmm1,xmm0
000000014000103B movd r8,xmm2
0000000140001040 movd rdx,xmm1
0000000140001045 lea rcx,[_fltused-10h (140003000h)]
000000014000104C call qword ptr [__imp_printf (1400020F0h)]

Là, le forçage en float est fait. A cause d'un modèle garanti plus
riche, le code pour le faire est plus carré. Il n'y a pas grand chose à
commenter, si ce n'est que le fait que la version la plus récente du
compilateur respecte le cast montre bien que c'est ce qu'il faut faire.

Je remarque aussi que j'avais écrit une bêtise en suggérant que tout ça
pouvait dépendre des bibliothèques dynamiques. Comme on alimente
printf() avec un double, c'est le compilateur qui décide s'il caste ou
non.

--
Pierre Maurette
Avatar
Pierre Maurette
, le 13/09/2009 a écrit :

[...]

Qu'en pensez vous ?



Si c'est effectivement un problème, on peut peut-être:

register float un_float;
...
printf("a=%.2f %.2fn", un_float=(float)a, value);
...
printf("a=%.2fn", un_float=(float)foo());
... etc.

Attention, c'est crade:

printf("a=%.2f %.2fn", un_float=(float)a, un_float=(float)b);

Couic...

--
Pierre Maurette
Avatar
Gabriel Dos Reis
Pierre Maurette writes:

[...]

| Je ne comprends pas votre approche quasi religieuse.

Une religion ne se comprend pas. Elle se pratique.

-- Gaby
1 2 3