J'utilise le compilateur Visual Studio TC pour Little Endian.
Ce qui suit est la pièce de code: la sortie est la suivante: p> 0x3F800000
a = 0.000000
c = 1.000000
7 Réponses :
jeter les variables
Cela ne répond pas à la question, qui est pourquoi i> cela se comporte comme il le fait, pas comment changer i> le comportement.
-1 Plus cela ne fonctionne même pas car il jette la valeur d'un flotteur. faire ce qu'il peut * ((flotteur *) & a) code>
J'ai compilé votre code dans GCC et le code généré est suit:
movl $0x3f800000, %eax movl %eax, -4(%ebp) movl $1065353216, -8(%ebp) leal -4(%ebp), %eax movl %eax, -12(%ebp) movl -12(%ebp), %eax movl (%eax), %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl -8(%ebp), %eax movl %eax, 4(%esp) movl $LC2, (%esp) call _printf flds -4(%ebp) fstpl 4(%esp) movl $LC3, (%esp) call _printf
Vous connaissez les registres ponctuels flottants ST0, ST1 (ces travaux de travail comme une pile. Vous appuyez sur (charge) un numéro de la mémoire et de tous les ST (x + 1) = STX et ST0 est réglé sur votre valeur) ...
Désolé d'avoir supprimé mon commentaire, il semble que le vôtre semble "accrocher". Votre réponse montre qu'il existe une pile «régulière» et une «pile à flotteur». Ceci n'est pas seulement faux mais x86 plate-forme spécifique et IMHO n'est pas utile en ce qui concerne la question. Le fait que x86 traite des registres flottants comme i> une pile n'affecte pas le comportement observé.
Je pense que la réponse à cette question est spécifique à la plate-forme. De cause que le comportement est indéfini. Spécifiquement sur la plate-forme X86, le comportement est causé par le fait que les flotteurs sont stockés dans des registres de flotteurs et tout le reste est en pile.
Nous I> ont aboyé le mauvais arbre, et medinoc a bien compris: % f code> pops A (64 bits) double code> hors de la pile et des impressions cette. Sur les machines low-endian, (32 bits) 0x3f800000 Code> converti en un double (64 bits) ne suffit pas pour apparaître avec la précision par défaut (6 chiffres). Essayez d'augmenter la précision, utilisez un type 64 bits pour A code> ou (et c'est ce que convaincu moi i>) appelle printf ("% f \ n", 0 , a) code> pour appuyer sur la valeur de A code> à l'endroit où il importe % f code>. Frères dans la défaite, +1 à Medinoc. (C'est toujours i> UB, bien sûr.)
comme Si une spécification de conversion n'est pas valide, le comportement est indéfini. Si un argument n'est pas le type correct pour la spécification de couverture correspondante, le comportement est indéfini. Strong> p>
Alors, ce que vous voyez ici, c'est ce que le constructeur de compilateur a décidé de se produire, ce qui peut être n'importe quoi. P> -wall code> états: AVERTISSEMENT: le format '% F' s'attend à ce que le type 'double', mais l'argument 2 a le type 'int' code>. Ceci est un comportement indéfini, comme expliqué également plus en détail ici . P>
Les compilateurs peuvent traiter Printf spécialement? Les compilateurs savent-ils comment traiter avec Printf?
Non mais ils définissent ce qui se passe en cas de conversion de type invalide.
Mais l'avertissement parle de la nullité de l'argument la vérifie contre le «spécificateur de format»?
ah oui vous avez raison et j'ai eu la raison pour laquelle aussi L1 . +1
int a= 0x3F800000;
printf("\na = %f", *(float*)&a);//1.0
Mes puissances psychiques me disent que le commentaire de Adam Liss est la bonne réponse: Si vous augmentez la précision de l'affichage, l'affichage doit être quelque chose comme Cela signifie également que cela devrait fonctionner: p> float code> Les arguments sont promus à double code>, donc la fonction printf () code> s'attend à ce que cela se produise: il attend une valeur de 64 bits sur la pile, mais obtient 32 bits plus des données à ordures qui se produisent de zéro. A = 0.00000000001 CODE>. P>
Medinoc merci beaucoup. Cela explique tout.
+1. J'ai passé une demi-heure à essayer de vous tromper. Le démontage a montré que double C code> est créé dans un registre FPU immédiatement (par opposition à float c code>), donc je soupçonnai à "corriger" votre résultat pour la mauvaise raison. Mais même enlever le double code> totalement obtenu la sortie observée pour A code>. Ensuite, j'ai soupçonné la manipulation spéciale pour les entiers 64 bits par GCC ... mais quand un fichier printf ("% f \ n", 0x0, 0x3FF0000) code> a donné 1.0 code> sans aucun < Code> Double Code> ou Long Long Long Code> impliqué, je devais admettre la défaite. En regardant les registres FPU était une chasse à l'oie sauvage.
Dans toute mise en œuvre C, il existe des règles sur la manière dont les paramètres sont transmis aux fonctions. Ces règles peuvent dire que les paramètres de certains types sont passés dans certains registres (par exemple, des types d'entiers dans des registres généraux et des types de points flottants dans des registres de points flottants distincts), que de grands arguments (tels que des structures avec de nombreux éléments) sont transmis sur le pile ou par un pointeur sur une copie de la structure, etc. p>
À l'intérieur d'une fonction appelée, la fonction recherche le paramètre qu'il attend dans les endroits que les règles spécifient. Lorsque vous passez un entier dans un argument sur En outre, de nombreuses implémentations C ont des types C'est pourquoi les spécificateurs de format que vous utilisez printf code> mais transmettez-le % f code> dans la chaîne de format, vous mettez un entier quelque part, mais indiquez printf code> chercher un flotteur (qui a été promu à un double). Si les règles de votre implication C spécifient que l'argument entier est passé au même endroit qu'un argument double, alors printf code> trouvera les bits de votre entier, mais il les interprétera comme un double. D'autre part, si les règles de votre implication C spécifient différents endroits pour les arguments, les bits de votre entier ne sont pas où printf code> recherche le double. Donc printf code> trouve des autres bits qui n'ont rien à voir avec votre entier. P>
int code> 32 bits et 64 bits % F code> est destiné à imprimer un double, pas un flotteur et la valeur de flotteur que vous passez est convertie en double avant d'appeler la fonction. Donc, même si printf code> trouve les bits de votre entier, il n'y a que 32 bits là-bas, mais printf code> utilise 64. donc le double code> qui est Imprimé est composé de 32 bits que vous avez passé et 32 autres bits, et ce n'est pas la valeur que vous avez destinée à imprimer. p>
Je rencontre le problème similaire, et enfin, je développe un moyen de résoudre le problème, je ne sais pas si c'est ce que vous voulez. Le point clé est que: vous devez passer un flotteur au lieu d'un entier.
0x3F800000 a = 0.000000 c = 1.000000 fp = 1.000000
Cela a toujours un comportement non défini, tous les mêmes problèmes initiaux restent que discutés dans les réponses antérieures et les commentaires précédents. Ce que vous avez fait est tombé sur une combinaison d'un alignement planétaire qui semble fonctionner à l'heure actuelle, sur un système avec une version compilatrice et une combinaison de paramètres.
Je ne suis pas aussi familier avec C, pouvez-vous expliquer quelle ligne de code contient légèrement un comportement indéfini?
Lignes 13,14,16 faire; et les lignes 11 et 12 pourraient faire. Je ne veux pas répéter ce qui a déjà été dit, alors lisez d'autres commentaires.
vous avez raison . Je viens de comprendre ce que j'ai fait, c'est exactement la même chose que les autres ont discuté auparavant.
c'est en raison d'un comportement indéfini.
Donner un spécificateur de format de
% f code> et donnant un argument de type INT.Printf () ne devine pas les types de variables donnés en tant que paramètres. Il suffit de faire confiance aux indicateurs spécifiés par l'utilisateur.
Tout argument code> float code> est promu
double code> quand il est passé à une fonction. Pour savoir exactement ce qui se passe, le compilateur produit la production d'assemblage et examine les différences dans le code générées pour chacune des déclarationsprintf () code>.Section 7.21.6 / 9 dit "Si une spécification de conversion n'est pas valide, le comportement n'est pas défini. Si un argument n'est pas le type correct de la spécification de conversion correspondante, le comportement n'est pas défini." B>. Ceci est pour FPRRTINF mais s'applique également à Printf.
@yoones apparemment, il vérifie ce L1 . Je suis en train de trouver la réponse à la façon dont cela fait. Modifier Je l'ai eu ici .
@Koushik: "comportement indéfini" n'est pas une cause de quelque chose. Un comportement indéfini est un manquant b> de définition, ce n'est donc qu'un manque de cause pour un comportement souhaité. La cause effective du comportement indésirable dépend des autres choses, telles que des détails de la mise en œuvre non définie par la norme C.
@Ericpostpischil "manque de cause pour un comportement souhaité". Mais le comportement non défini peut également être le manque de cause de comportement indésirable aussi non ?.
@Koushik: Le comportement non défini est toujours non souhaité, au moins à l'extérieur du laboratoire.
* PTR CODE> Cause UB en violant la règle d'aliasing stricte (comme toutes les "solutions" conseillent d'écrire* (flotteur *) & a code> ou similaire)