2009-11-22 5 views
1

Je sais que c'est mauvais et gcc vous donnera un avertissement à ce sujet, mais pourquoi cela fonctionne-t-il (c'est-à-dire les numéros sont imprimés correctement, avec une certaine différence d'arrondi)?Des pointeurs d'impression de résultats bizarres comme flottant dans C

int main() { 
    float *f = (float*) malloc(sizeof(float)); 
    *f = 123.456; 
    printf("%f\n", *f); 
    printf("%f\n", f); 
    return 0; 
} 

Edit: Oui, j'utilise gcc avec une machine 32 bits. J'étais curieux de voir quels résultats j'obtiendrais avec d'autres compilateurs.

Je mêlais des choses un peu plus après la suggestion de Christoph:

int main() { 
    float *f = (float*) malloc(sizeof(float)); 
    *f = 123.456; 
    printf("%f\n", f); // this 
    printf("%f\n", *f); 
    printf("%f\n", f); // that 
    return 0; 
} 

Il en résulte la première impression printf une valeur différente de la dernière printf, en dépit d'être identiques.

+0

presque correct: les arguments sont passés par valeur, mais le fait de pousser le valeur – Christoph

+0

vous devez publier la sortie réelle que vous obtenez. Suggérez-vous que le 2ème printf imprime réellement '123' ou quelque chose comme ça? – JustJeff

Répondre

11

Réorganisez les instructions printf() et vous verrez que cela ne fonctionnera plus, donc GCC ne résout définitivement rien derrière votre dos.

En quoi cela fonctionne-t-il? En raison de la promotion par défaut des arguments variables, vous allez passer un double avec votre premier appel. Comme les pointeurs sur votre système semblent être 32 bits, le second appel écrase seulement la moitié inférieure de la valeur à virgule flottante de 64 bits.

En ce qui concerne votre exemple modifié:

  • le premier appel affichera une valeur double précision où les 32bits plus élevés sont des ordures et plus la valeur binaire du pointeur f
  • la deuxième impressions d'appel les le *f promu à la double précision
  • le troisième appel imprime une valeur de double précision avec les 32 bits supérieurs provenant de (double)*f (car ces bits restent sur la pile du dernier appel); Comme dans le premier cas, les bits inférieurs reviendront du pointeur f
1

Les numéros ne s'impriment pas correctement pour moi.

Sortie:

123.456001 
0.000000 

J'utilise VC++ 2009.

1

printf n'a pas connaissance sur le type réel d'arguments. Il analyse juste la chaîne de format et interprète les données sur la pile en conséquence. Par coïncidence (plus ou moins =)), le pointeur sur float a la même taille que float (32 bits) sur votre plate-forme, de sorte que la pile est équilibrée après la suppression de cet argument.

Sur d'autres plates-formes ou avec d'autres types de données, cela peut ne pas fonctionner.