Wie ist die Umwandlung von float/double nach int behandelt in printf?
Betrachten Sie dieses Programm
int main()
{
float f = 11.22;
double d = 44.55;
int i,j;
i = f; //cast float to int
j = d; //cast double to int
printf("i = %d, j = %d, f = %d, d = %d", i,j,f,d);
//This prints the following:
//i = 11, j = 44, f = -536870912, d = 1076261027
return 0;
}
Kann mir jemand erklären, warum das casting von double - /float-zu-int-funktioniert einwandfrei in dem ersten Fall, und nicht arbeiten, wenn getan, in printf?
Dieses Programm wurde kompiliert gcc-4.1.2 auf 32-bit-linux-Maschine.
EDIT:
Zach ' s Antwort scheint logisch, D. H. die Nutzung der format-Spezifizierer, um herauszufinden, was zu pop vom Stapel. Aber dann betrachten Sie diese follow-up-Frage:
int main()
{
char c = 'd'; //sizeof c is 1, however sizeof character literal
//'d' is equal to sizeof(int) in ANSI C
printf("lit = %c, lit = %d , c = %c, c = %d", 'd', 'd', c, c);
//this prints: lit = d, lit = 100 , c = d, c = 100
//how does printf here pop off the right number of bytes even when
//the size represented by format specifiers doesn't actually match
//the size of the passed arguments(char(1 byte) & char_literal(4 bytes))
return 0;
}
Wie funktioniert das?
Ich hatte eine ähnliche Zweifel. Siehe diesen thread: stackoverflow.com/questions/2377733/how-does-this-program-work
char ist ein einzelnes Zeichen - es ist einfach eine 8-bit-Ganzzahl. Wenn Sie tun, jede Art von operation auf Integrale Art, die kleiner als int sind, werden Sie befördert zu integer. Dies gilt auch, wenn eine Funktion aufrufen. Also eigentlich ist es nicht nur Zufall verursacht die printf-Aufruf zu arbeiten, dieses Verhalten definiert ist. Praktisch gesprochen, in den meisten C-ABIs man immer reservieren Sie mindestens eine Maschine pro Wort-variable auf den stack gelegt.
Ja,
Wie hat mein Kommentar gelöscht wurde?
Sehr seltsam. Diese Website hat eine Menge von Moderatoren und manchmal Dinge tun, nach dem Zufallsprinzip verschwinden.
char ist ein einzelnes Zeichen - es ist einfach eine 8-bit-Ganzzahl. Wenn Sie tun, jede Art von operation auf Integrale Art, die kleiner als int sind, werden Sie befördert zu integer. Dies gilt auch, wenn eine Funktion aufrufen. Also eigentlich ist es nicht nur Zufall verursacht die printf-Aufruf zu arbeiten, dieses Verhalten definiert ist. Praktisch gesprochen, in den meisten C-ABIs man immer reservieren Sie mindestens eine Maschine pro Wort-variable auf den stack gelegt.
Ja,
<stdarg>
parameter übergeben berücksichtigt nur Arten gefördert, die nach default argument promotions (C11 §6.5.2.2/6, §7.16.1.1/2), das garantiert, dass char
und int
sind kompatibel gemacht. Dies ist jedoch nicht ganz das gleiche wie die Aktionen verwendet, für die Arithmetik. Auch, es ist gefährlich, auf Grund der Sprache in Bezug auf das ABI. Die Bestätigung, dass es OK ist wirklich erfordert eine überprüfung der Regeln.Wie hat mein Kommentar gelöscht wurde?
Sehr seltsam. Diese Website hat eine Menge von Moderatoren und manchmal Dinge tun, nach dem Zufallsprinzip verschwinden.
InformationsquelleAutor Sandip | 2010-03-08
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den
printf
- Funktion verwendet die format-Spezifizierer, um herauszufinden, was zu pop vom Stapel. Also, wenn es sieht%d
es erscheint aus 4 bytes und interpretiert Sie als eineint
die falsch ist (die binäre Darstellung von(float)3.0
ist nicht das gleiche wie(int)3
).Müssen Sie entweder die
%f
Formatbezeichner oder Stimmen die Argumenteint
. Wenn Sie eine neue genug-version vongcc
, dann einschalten deutlichere Warnungen Fänge dieser Art von Fehler:Reaktion auf den bearbeiteten Teil der Frage:
C die integer-promotion-Regeln sagen, dass alle Typen, die kleiner als
int
befördert zuint
wenn übergeben, wie ein vararg. Also in deinem Fall, die'd'
immer gefördert werden, um eineint
, dann printf knallen aus eineint
und Gießen zu einemchar
. Die beste Referenz, die ich finden konnte für dieses Verhalten war dieser blog-Eintrag.Ich habe ein follow-up-Frage, finden Sie das bearbeitete Teil meiner Frage. Bitte kommentieren, wenn die Frage nicht klar...danke
Es ist wahr, dass
char
Argumente bekommen, gefördert zuint
beim übergeben der variable Teil der argument-Liste (dies ist, was passiert, wennc
übergeben wird in dem Beispiel), aber Zeichen-literalen Konstanten (wie'd'
) sind bereits vom Typint
. (Beachten Sie auch, dass in der Theorie, unter bestimmten Compilerchar
Argumente, die gefördert werden könntenunsigned int
statt).gute Antwort. Dieses Verhalten ist nicht printf, sondern halten für alle variadischen Funktionen. Wie es funktioniert, ist gut dokumentiert va_arg-manpage, einschließlich der Förderung der chars zu int. Für ein Beispiel der Anwendung werden Sie sehen können, meine Antwort in stackoverflow.com/questions/1688942
InformationsquelleAutor Zach Hirsch
Es gibt keine solche Sache als "casting zu
int
imprintf
".printf
nicht tun und kann nicht jedes casting. Inkonsistente format specifier führt zu undefiniertem Verhalten.In der Praxis
printf
einfach empfängt die Rohdaten und interpretiert Sie als stillschweigend von der Formatbezeichner. Wenn Sie es übergebendouble
Wert, und geben Sie eineint
Formatbezeichner (wie%d
),printf
nehmen, dassdouble
Wert und blind umzudeuten einint
. Die Ergebnisse werden völlig unberechenbar (das ist der Grund, warum tut dieser formal bewirkt Undefiniertes Verhalten in C).A. Schneider: Wirklich? Was ist mit Situationen, in denen der format-string ist eine run-time-Wert? Wie erwarten Sie den compiler zu "cast" nichts mehr, selbst wenn "conversion specifiers sind Teil der standard"? Generell aber ist dies ein grundlegendes Prinzip der Sprache C design: die standard-Bibliothek nicht verlassen sich auf die "magischen" Eigenschaften der compiler (mit wenigen Ausnahmen vielleicht). Nahezu jede Bibliothek, die Funktion kann implementiert werden, indem der Benutzer in der C-Sprache selbst. Solange die Sprache C folgt, dass grundsätzlich
printf
werden nicht "augmented" mit jedem compiler-magic.Zugegeben, ich glaube nicht, dass der run-time format strings (denn in aller Wirklichkeit: Wann ist Sie das Letzte mal verwendet?). Aber der standard konnte zwischen den Fällen-sehen Sie, was Sie getan haben, um
sizeof
. Die Darsteller: Es ist ziemlich offensichtlich, dass der compiler weiß, wie die Besetzung Arten im Allgemeinen, also ich kann nicht erkennen, keine zusätzliche Magie hier, und ich denke auch, dass die Besetzung wohl sein könnte implementiert in C sowieso. Wie eine große, wenn/sonst wenn der Schalter über die Umwandlung Betreiber, und dann die entsprechenden wirft. Die brechen ändern würde, eher werden die sich verändernden Semantik der Ellipse Prototyp.Als Vorschlag für eine Umsetzung würde ich erwarten, dass in dem Fall, wo die parameter-Typen nach der letzten deklarierten parameter sind bekannt und/oder können hergeleitet werden, die zur compile-Zeit (wie in der statischen fomat string von printf () der compiler erzeugt eine Unbenannte Funktion Prototyp mit der angegebenen Anzahl von Parametern mit den gegebenen Typen und behandelt die Argumente, wie bei jeder anderen gewöhnlichen Funktion; z.B. er weigert sich zu kompilieren oder verknüpfen, wenn die Argumente sind nicht kompatibel mit den abgeleiteten parameter geben. Das wäre wahrscheinlich ähnlich wie einige Instanzen von type-inference in modernem C++, d.h. die Mechanismen existieren.
InformationsquelleAutor AnT
Jack ' s Antwort erklärt, wie Ihr problem zu lösen. Ich werde erklären, warum Sie immer Ihre unerwartete Ergebnisse. Dein code ist äquivalent zu:
Der Grund ist, dass
f
undd
übergebenprintf
als Werte, und diese Werte werden interpretiert alsint
s. Das ändert nichts an der binären Wert, so dass die Anzahl angezeigt wird, ist die binäre Darstellung einesfloat
oder einedouble
. Die tatsächliche Besetzung vonfloat
zuint
ist sehr viel komplexer in der generierten assembly.Mein code funktioniert (für mich und wohl auch für ihn), was sein code ist zu tun (für ihn). Beide sind undefiniert Verhalten, so dass weder das eine ist garantiert nichts zu tun insbesondere.
InformationsquelleAutor Chris Lutz
Weil Sie nicht die float-format specifier, versuchen Sie es mit:
Sonst, wenn Sie wollen, 4 ints, die Sie haben, um Sie zu werfen, bevor er das argument an printf:
InformationsquelleAutor Jack
Den Grund Ihrer follow-up-code funktioniert, weil der Charakter konstant gefördert, die einen int-Wert, bevor es auf dem Stapel abgelegt. So printf off erscheint 4 Byte für %c und %d an. In der Tat, Zeichenkonstanten sind vom Typ int und nicht vom Typ char. C ist merkwürdig, dass Art und Weise.
InformationsquelleAutor MtnViewJohn
printf verwendet variable length argument lists, das heißt, Sie brauchen, um die Art von Informationen. Sie sind die Bereitstellung der falschen Informationen, so kommt er Durcheinander. Jack bietet die praktische Lösung.
InformationsquelleAutor Matthew Flaschen
Es ist erwähnenswert, dass
printf
, wird eine Funktion mit einer variable-length argument list, erhält nie eine float; float Argumente der "alten Schule" gefördert verdoppelt.Einer aktuellen standard-Entwurf führt die "alte Schule" Standard-Aktionen erste (n1570, 6.5.2.2/6):
Dann es wird erläutert, variable argument-Listen (6.5.2.2/7):
Folge für
printf
ist, dass es unmöglich ist, "print" ein echter Schwimmer. Ein float-Ausdruck ist stets auf die Förderung zu verdoppeln, das ist ein 8 byte-Wert für die IEEE-754-Implementierungen. Diese Förderung erfolgt auf der aufrufenden Seite; printf haben bereits eine 8-byte-argument auf den stack, wenn seine Ausführung beginnt.Weisen wir
11.22
zu einem Doppelbett und Inhalte, mit meinem x86_64-pc-cygwin-gcc sehe ich die byte-Reihenfolge 000000e0a3702640.Erklärt, dass der int-Wert gedruckt von
printf
: Ints auf dieses Ziel immer noch 4 bytes, so dass nur die ersten vier bytes 000000e0 bewertet werden, und wieder in little-endian, d.h. als 0xe0000000. Dies ist -536870912 in dezimal.Wenn wir umkehren alle 8 bytes, weil der Intel-Prozessor speichert Doppelzimmer in der little-endian-auch wir bekommen 402670a3e0000000. Wir können überprüfen Sie den Wert dieses byte-Reihenfolge stellt im IEEE-format auf dieser Website; es ist in der Nähe von 1.122E1, d.h. 11.22, das erwartete Ergebnis.
InformationsquelleAutor Peter A. Schneider