2016-06-13 31 views
-6

Warum funktioniert der folgende Code auf IA-32 und x86-64 völlig anders?a ist ein Double, printf ("% d", a); funktioniert anders in IA32 und IA32-64

#include <stdio.h> 
int main() { 
    double a = 10; 
    printf("a = %d\n", a); 
    return 0; 
} 

auf IA-32, das Ergebnis ist immer 0. jedoch auf x86-64 das Ergebnis irgendetwas zwischen MAX_INT und MIN_INT sein kann.

+2

Es ist undefiniertes Verhalten, 'printf' mit Argumenten aufzurufen, die nicht mit der Formatzeichenfolge übereinstimmen. –

+0

Nicht wirklich mein Bereich, aber es sieht so aus, als ob x86-64 'double' und' int' Argumente in verschiedenen Registern übergeben würden - also 'a' wird an' printf() 'an einer Stelle übergeben, aber bei der Verarbeitung der format string 'printf()' sucht nach einem 'int'-Argument in einem anderen Register, in dem kein Wert enthalten ist, da es nicht zur Übergabe eines Arguments verwendet wurde. – Dmitri

Antwort

1

%d wird tatsächlich zum Drucken verwendet int. Historisch stand die d für "dezimal", im Gegensatz zu o für oktale und x für hexadezimale.

Zum Drucken double sollten Sie %e, %f oder %g verwenden.

Die Verwendung des falschen Formatbezeichners verursacht undefined behaviour, was bedeutet, dass alles passieren kann, einschließlich unerwarteter Ergebnisse.

+0

Sie könnten die korrekten Formate für den Typ "double" erwähnen: '"% g "', '"% f "' und '"% e "'. –

+0

Ich kenne das richtige Format, um doppelt zu drucken. Dies ist eine Frage, die von meinem Lehrer gestellt wurde, also denke ich, dass dahinter etwas Mysteriöses steckt. Vielen Dank! –

+0

@MartinGao Vergessen Sie nicht, diese Website mit der Antwort zu belohnen, wenn Sie Ihre Aufgabe eingeben –

0

Ein Argument an printf() übergeben, das nicht mit den Formatbezeichnern in der Formatzeichenfolge übereinstimmt, ist undefiniertes Verhalten ... und mit undefiniertem Verhalten kann alles passieren und die Ergebnisse sind nicht notwendigerweise konsistent von einer Instanz zur anderen - also sollte es vermieden werden.

Warum sehen Sie einen Unterschied zwischen x86 (32-Bit) und x86-64, ist es wahrscheinlich aufgrund von Unterschieden in der Art, wie Parameter in jedem Fall übergeben werden.

im x86 Fall werden die Argumente printf() wahrscheinlich auf dem Stapel geführt werden, ausgerichtet auf die 4-Byte-Grenzen - so dass, wenn der Prozesse printf()%d Spezifizierer liest eine 4-Byte-int aus dem Stapel, die eigentlich die unteren 4 Bytes von a. Da a war 10 diese Bytes haben keine Bits gesetzt, so sind sie als int Wert von 0.

Im x86-64 Fall interpretiert werden die Argumente zu printf() alle in Registern übergeben (obwohl einige auf das sein würde Stack, wenn es genug von ihnen gab) ... aber double Argumente werden in verschiedenen Registern als int Argumente (wie% xmm0 statt% rsi) übergeben. Also, wenn printf() versucht, ein int Argument zu den %d Spezifizierer zu verarbeiten, es dauert es von einem anderen Register, das die a wurde übergeben, und verwendet, was Müll-Wert im Register anstelle der unteren Bytes von a übrig gelassen wurde, und interpretiert das als etwas Müll int Wert.

+0

Frage Im x86-Fall, nach dem IEEE754, weiß ich, warum es immer 0 ist. Aber ich weiß wenig über Argumente im x86-64 Fall übergeben. Ich schaue auf den Asm-Code mit gdb und finde es ** a ** via **% xmm0 **, also denke ich, dass du recht hast. –

+0

Eine interessante Konsequenz dieses Effekts ist, dass Sie Integer- und Gleitkomma-Argumente manchmal in der falschen Reihenfolge übergeben können und dennoch normales Verhalten erhalten. Mit 64-Bit auf meinem System bekomme ich identische Ergebnisse zwischen 'printf ("% d,% f \ n ", 1234, 10,7) und' printf ("% d,% f \ n", 10.7,1234) ; 'weil' 1234' das erste 'int' ist (nach der Formatzeichenfolge) und' 10.7' das erste 'double' ist, egal in welcher Reihenfolge sie übergeben werden. – Dmitri

+0

Ich bekomme die gleichen Ergebnisse auf meinem System. Du hast mein Problem vollständig gelöst und mir gesagt, was wirklich in diesem undefinierten Verhalten passiert ~ Danke ~ –