2009-11-22 18 views
5

Ich habe, das C Primer Plus Buch zu lesen und bekam zu diesem BeispielLange Doppel in C

#include <stdio.h> 
int main(void) 
{ 
    float aboat = 32000.0; 
    double abet = 2.14e9; 
    long double dip = 5.32e-5; 

    printf("%f can be written %e\n", aboat, aboat); 
    printf("%f can be written %e\n", abet, abet); 
    printf("%f can be written %e\n", dip, dip); 

    return 0; 
} 

Nachdem ich diese auf meinem macbook lief ich am Ausgang ziemlich schockiert war:

32000.000000 can be written 3.200000e+04 
2140000000.000000 can be written 2.140000e+09 
2140000000.000000 can be written 2.140000e+09 

So Ich schaute mich um und fand heraus, dass das korrekte Format, um lange doppelte anzuzeigen, %Lf zu verwenden ist. Allerdings kann ich immer noch nicht verstehen, warum ich den doppelten abet Wert bekam statt dem, was ich bekam, als ich es lief auf Cygwin, Ubuntu und iDeneb die

-1950228512509697486020297654959439872418023994430148306244153100897726713609 
013030397828640261329800797420159101801613476402327600937901161313172717568.0 
00000 can be written 2.725000e+02 

grob sind Irgendwelche Ideen?

+0

Sind Sie sicher, dass Sie genau diesen Code hatte? Ich habe es einfach auf meinem MacBook - MacOS X 10.5.8 (GCC 4.0.1) ausgeführt und Ihr Cygwin-Ergebnis erhalten. –

+0

Ja, ich habe es nochmal überprüft. Btw ich laufe MacOS X 10.6.2 (GCC 4.2.1) – reubensammut

+0

Wirklich bekomme ich die erwartete unsinnige Antwort auf Mac. Rätselhaft. Running 'Otool -L 'auf meiner ausführbaren Datei sagt mir, dass es gegen/usr/lib/libSystem.B.dylib Version 111.1.4 ausgeführt wird; Das ist die Bibliothek, die 'printf' bereitstellt. Wenn Sie die gleiche Version dieser Bibliothek haben, sollten Sie die gleiche Antwort erhalten. –

Antwort

7

Versuchen Sie, die varargs Aufrufkonvention auf OSX zu betrachten, das könnte es erklären.

I die Compiler erraten übergibt die ersten long double Parameter auf dem Stapel (oder in einem FPU-Register), und den ersten Parameter double in CPU-Register (oder auf dem Stapel). Wie auch immer, sie sind an verschiedenen Orten passiert. Wenn also der dritte Anruf getätigt wird, liegt der Wert des zweiten Anrufs noch herum (und der Angerufene nimmt ihn auf). Aber das ist nur eine Vermutung.

+0

+1 Psychische Fehlersuche :) – Andomar

3

Vielleicht ist die 64-Bit-ABI in der Weise anders, dass printf nach% f-Argumenten an einer völlig anderen Stelle als% LF-Argumente sucht.

Versuchen Sie, sich den Baugruppenausgang anzuschauen (gcc -S), um zu sehen, ob dies zutrifft.

+0

Ich werde einen Blick auf die Montage und sehen, ob es der Fall ist, obwohl es einige Zeit dauern kann, weil ich nicht wirklich zuversichtlich in Assembly vor allem mit der x86-64 one – reubensammut

4

Die C Standard Library ‚s printf() Funktion ist ein Beispiel eines variadic function, das heißt eine, die eine unterschiedliche Anzahl von Argumenten nehmen. Wie die Sprache C dies implementiert, muss die aufgerufene Funktion wissen, welcher Typ von Argumenten in welcher Reihenfolge übergeben wurde, damit sie sie richtig interpretieren kann. Aus diesem Grund übergeben Sie eine Format-Zeichenfolge, so dass printf() die Daten, die gedruckt werden müssen, richtig erkennen kann.

Wenn eine Variadic-Funktion die übergebenen Argumente falsch interpretiert, gibt der C-Standard an, dass das Verhalten undefined ist, was alles passieren kann (C89-Standard Para 4.8.1.2). In Ihrem Fall, wo Sie nicht übereinstimmende Formate und Werte an printf() übergeben, ist das was passiert. Wenn Sie jedoch einen anständigen Compiler haben und Ihre Warnstufen zu etwas Sinnvollem werden, sollten Sie während der Kompilierung darüber gewarnt werden. Zum Beispiel auf Cygwin, erhalte ich:

$ make go 
cc -g -W -Wall -Wwrite-strings -ansi -pedantic go.c -o go 
go.c: In function `main': 
go.c:10: warning: double format, long double arg (arg 2) 
go.c:10: warning: double format, long double arg (arg 3) 
go.c:10: warning: double format, long double arg (arg 2) 
go.c:10: warning: double format, long double arg (arg 3) 
$ 

Wie, warum Sie speziell bekommen, was Sie sehen, das von der jeweiligen Implementierung ab. In der Praxis ist es wahrscheinlich, dass Ihre spezielle Implementierung von printf() die erste Hälfte Ihrer long double als double interpretiert und den Wert druckt, der diesem bestimmten Bitmuster entspricht. Wie der Standard jedoch sagt, könnte es tun, was es will.

+0

Beachten Sie auch, dass mit variadic Funktionen, Float-Parameter werden immer befördert und als "double" übergeben. Integrale Parameter 'char' und' short' werden zu 'int' (oder' unsigned int') hochgestuft. – tomlogic

+0

@tomlogic: K & R hatte einen guten Grund, alle Gleitkommawerte in variablen Funktionen auf denselben Typ zu zwingen; ANSI C hätte nachziehen sollen, indem es Prototypen erlaubt, einen Fließkommatyp zu bestimmen, in den alle Gleitkommawerte umgewandelt werden. Viele Compiler für Maschinen, die Berechnungen unter Verwendung eines 80-Bit-Fließkommawerts ausgeführt haben, arbeiteten um das Fehlen eines solchen Merkmals herum, indem sie "lange doppelte" 64 Bits machten und keinen 80-Bit-Typ lieferten, was zu einer Verschlechterung der Fließkomma-Mathematik führte geht bis heute weiter. – supercat

1

Ich lese C Primer Plus, wie Sie habe ich das gleiche bemerkt. Sehen Sie, wie ich die Formatbezeichner für die dritte printf-Anweisung geändert habe.

#include <stdio.h> 
#include <inttypes.h> 

int main(void){ 

    float aboat = 320000.0; 
    double abet = 2.214e9; 
    long double dip = 5.32e-5; 

    printf("%f can be written %e\n", aboat, aboat); 
    printf("%f can be written %e\n", abet, abet); 
    printf("%Lf can be written %Le\n", dip, dip); 

    return 0; 
} 

Ergebnisse nach

320000.000000 can be written 3.200000e+05 
2214000000.000000 can be written 2.214000e+09 
0.000053 can be written 5.320000e-05 
3

Verwenden Spezifizierer als %LF für die long double statt %lf oder %f die Formatbezeich ändern. %LF hat immer eine andere Bedeutung als %lf.

#include <stdio.h> 
int main(void) 
{ 
    float aboat = 32000.0; 
    double abet = 2.14e9; 
    long double dip = 5.32e-5L; 

    printf("%f can be written %e\n", aboat, aboat); 
    printf("%f can be written %e\n", abet, abet); 
    printf("%LF can be written %LE\n", dip, dip); 

    return 0; 
} 

Ausgang:

The output; transcript below

32000.000000 can be written 3.200000e+04 
2140000000.000000 can be written 2.140000e+09 
0.000053 can be written 5.320000E-05 
+0

Das ist eine gute Antwort. Bitte posten Sie mehr! – wizzwizz4