Zunächst einmal, wie in mehreren anderen Antworten erwähnt, aber meines Erachtens nicht klar genug formuliert: In den meisten Kontexten, in denen eine Bibliotheksfunktion ein oder ein Argument verwendet, funktioniert es, eine Ganzzahl bereitzustellen . Der Compiler fügt automatisch eine Konvertierung ein. Zum Beispiel ist es gut definiert und verhält sich genau so , und dasselbe gilt für alle anderen dort verwendeten Ausdrücke vom Typ Ganzzahl.double
float
sqrt(0)
sqrt((double)0)
printf
ist anders. Es ist anders, weil es eine variable Anzahl von Argumenten benötigt. Sein Funktionsprototyp ist
extern int printf(const char *fmt, ...);
Deshalb, wenn Sie schreiben
printf(message, 0);
Der Compiler hat keine Informationen darüber, welcher Typ dieses zweite Argument printf
erwartet . Es hat nur den Typ des Argumentausdrucks, der verwendet werden soll int
. Im Gegensatz zu den meisten Bibliotheksfunktionen müssen Sie als Programmierer sicherstellen, dass die Argumentliste den Erwartungen der Formatzeichenfolge entspricht.
(Moderne Compiler können in eine Formatzeichenfolge schauen und Ihnen mitteilen, dass Sie eine Typinkongruenz haben, aber sie werden keine Konvertierungen einfügen, um das zu erreichen, was Sie gemeint haben, da Ihr Code jetzt besser kaputt gehen sollte, wenn Sie es bemerken , als Jahre später, als es mit einem weniger hilfreichen Compiler neu erstellt wurde.)
Die andere Hälfte der Frage lautete: Angesichts der Tatsache, dass (int) 0 und (float) 0.0 auf den meisten modernen Systemen beide als 32 Bit dargestellt werden, die alle Null sind, warum funktioniert es nicht aus Versehen? Der C-Standard sagt nur "das ist nicht erforderlich, um zu funktionieren, Sie sind allein", aber lassen Sie mich die zwei häufigsten Gründe darlegen, warum es nicht funktionieren würde; Das wird Ihnen wahrscheinlich helfen zu verstehen, warum es nicht erforderlich ist.
Erstens, aus historischen Gründen, wenn Sie einen Pass float
durch eine variable Argumentliste wird sie gefördert zu double
, die auf den meisten modernen Systemen ist 64 Bit breit. printf("%f", 0)
Übergibt also nur 32 Null-Bits an einen Angerufenen, der 64 davon erwartet.
Der zweite, ebenso wichtige Grund ist, dass Gleitkommafunktionsargumente an einer anderen Stelle als ganzzahlige Argumente übergeben werden können. Beispielsweise haben die meisten CPUs separate Registerdateien für Ganzzahlen und Gleitkommawerte. Daher können die Argumente 0 bis 4 in den Registern r0 bis r4 enthalten sein, wenn sie Ganzzahlen sind, aber f0 bis f4, wenn sie Gleitkommawerte sind. So printf("%f", 0)
sieht im Register f1 für die Null, aber es ist nicht , dass es überhaupt nicht .
printf
erwartet eindouble
, und du gibst es einint
.float
undint
kann auf Ihrem Computer dieselbe Größe haben, wird jedoch0.0f
tatsächlich in eine konvertiert,double
wenn sie in eine Liste mit variablen Argumenten verschoben wird (undprintf
erwartet dies). Kurz gesagt, Sie erfüllen Ihr Schnäppchen nicht mitprintf
den von Ihnen verwendeten Spezifizierern und den von Ihnen angegebenen Argumenten.