Antworten:
Das liegt daran, %d
dass erwartet wird, int
aber Sie haben einen Float bereitgestellt.
Verwenden Sie %e
/ %f
/ %g
den Schwimmer zu drucken.
Warum 0 gedruckt wird: Die Gleitkommazahl wird double
vor dem Senden an konvertiert printf
. Die Zahl 1234.5 in doppelter Darstellung in Little Endian ist
00 00 00 00 00 4A 93 40
A %d
verbraucht eine 32-Bit-Ganzzahl, sodass eine Null gedruckt wird. (Als Test könnten printf("%d, %d\n", 1234.5f);
Sie Sie könnten auf Ausgabe bekommen 0, 1083394560
.)
Warum wird der als Prototyp von printf von 6.5.2.2/7 float
konvertiert ?double
int printf(const char*, ...)
Die Auslassungsnotation in einem Funktionsprototyp-Deklarator bewirkt, dass die Konvertierung des Argumenttyps nach dem zuletzt deklarierten Parameter gestoppt wird. Die Standardargumentwerbung wird für nachfolgende Argumente durchgeführt.
und vom 6.5.2.2/6,
Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der keinen Prototyp enthält, werden die Ganzzahl-Heraufstufungen für jedes Argument ausgeführt und Argumente mit Typ
float
werden heraufgestuftdouble
. Diese werden als Standardargumentwerbung bezeichnet .
(Danke Alok, dass du das herausgefunden hast.)
printf
es sich um eine variadische Funktion handelt und der Standard besagt, dass für variadische Funktionen a vor dem Übergeben in a float
konvertiert wird double
.
printf()
ruft Undefiniertes Verhalten auf .
Technisch gibt sprechen , ist nicht die printf
, die jeweils ihre Bibliothek implementiert eigene, und daher Ihre Methode der zu Studie versucht , printf
indem Sie ‚Verhalten , was Sie tun , ist nicht von großem Nutzen sein wird. Möglicherweise versuchen Sie, das Verhalten printf
Ihres Systems zu untersuchen. In diesem Fall sollten Sie die Dokumentation lesen und im Quellcode nachsehen, printf
ob er für Ihre Bibliothek verfügbar ist.
Auf meinem Macbook erhalte ich beispielsweise die Ausgabe 1606416304
mit Ihrem Programm.
Wenn Sie jedoch a float
an eine variable Funktion übergeben, float
wird das als übergeben double
. Ihr Programm entspricht also der Deklaration a
als double
.
Um die Bytes von a zu untersuchen double
, können Sie diese Antwort auf eine aktuelle Frage hier auf SO sehen.
Lass uns das tun:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
unsigned char *p = (unsigned char *)&a;
size_t i;
printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
for (i=0; i < sizeof a; ++i)
printf("%02x ", p[i]);
putchar('\n');
return 0;
}
Wenn ich das obige Programm ausführe, erhalte ich:
size of double: 8, int: 4
00 00 00 00 00 4a 93 40
Die ersten vier Bytes von haben double
sich also als 0 herausgestellt, weshalb Sie möglicherweise 0
die Ausgabe Ihres printf
Anrufs erhalten haben.
Für interessantere Ergebnisse können wir das Programm ein wenig ändern:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
int b = 42;
printf("%d %d\n", a, b);
return 0;
}
Wenn ich das obige Programm auf meinem Macbook ausführe, erhalte ich:
42 1606416384
Mit dem gleichen Programm auf einem Linux-Computer bekomme ich:
0 1083394560
int
Argumente in anderen Registern als double
Argumente übergeben werden. printf
mit %d
nimmt das int
Argument, das 42 ist, und das zweite %d
druckt wahrscheinlich Junk, da es kein zweites int
Argument gab.
Der %d
Bezeichner gibt printf
an, eine Ganzzahl zu erwarten. Die ersten vier (oder zwei, je nach Plattform) Bytes des Floats werden also als Ganzzahl interpretiert. Wenn sie zufällig Null sind, wird eine Null gedruckt
Die binäre Darstellung von 1234.5 ist so etwas wie
1.00110100101 * 2^10 (exponent is decimal ...)
Bei einem C-Compiler, der float
tatsächlich als IEEE754-Doppelwerte dargestellt wird, wären die Bytes (wenn ich keinen Fehler gemacht hätte)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
Auf einem Intel (x86) -System mit geringer Endianess (dh das niedrigstwertige Byte steht an erster Stelle) wird diese Bytesequenz umgekehrt, sodass die ersten vier Bytes Null sind. Das heißt, was wird printf
gedruckt ...
In diesem Wikipedia-Artikel finden Sie eine Gleitkomma-Darstellung gemäß IEEE754.
Es liegt an der Darstellung eines Floats in Binärform. Bei der Konvertierung in eine Ganzzahl bleibt 0 übrig.
Weil Sie undefiniertes Verhalten aufgerufen haben: Sie haben den Vertrag der printf () -Methode verletzt, indem Sie sie über ihre Parametertypen belogen haben, sodass der Compiler frei tun kann, was er will. Es könnte dazu führen, dass das Programm "dksjalk is a ninnyhead !!!" und technisch wäre es immer noch richtig.
Der Grund ist, dass dies printf()
eine ziemlich dumme Funktion ist. Typen werden überhaupt nicht überprüft. Wenn Sie sagen, dass das erste Argument ein ist int
(und das ist es, womit Sie sagen %d
), glaubt es Ihnen und es braucht nur die Bytes, die für ein benötigt werden int
. In diesem Fall, wenn Ihr Computer vier Byte int
und acht Byte verwendet double
(das float
wird in ein double
Inneres konvertiert printf()
), sind die ersten vier Bytes a
nur Nullen, und dies wird gedruckt.
Da Sie es auch mit C ++ markiert haben, führt dieser Code die Konvertierung wie erwartet durch:
#include <iostream.h>
int main() {
float a = 1234.5f;
std::cout << a << " " << (int)a << "\n";
return 0;
}
Ausgabe:
1234.5 1234
%d
ist dezimal
%f
ist float
Weitere davon finden Sie hier .
Sie erhalten 0, weil Gleitkommazahlen und Ganzzahlen unterschiedlich dargestellt werden.
Sie müssen nur den entsprechenden Formatbezeichner (% d,% f,% s usw.) Mit dem entsprechenden Datentyp (int, float, string usw.) verwenden.
Es ist keine ganze Zahl. Versuchen Sie es mit %f
.