Ausgabe printf()
-
Hallo,
ich habe eine Frage zu folgendem Code.
#include <stdio.h> int main() { printf("%f\n", (8/5)/2); printf("%f\n", (float) 5/2); printf("%f\n", (8/5)/2); return 0; }
Die 3. und 5. Zeile sind identisch. Bei der Ausgabe allerdings ist der Wert verschieden. Wie kann das sein, dass bei syntaktisch identischem Code verschiedene Ausgaben erzeugt werden? Ich habe keine Variablen deklariert, sondern nur Terme für die Platzhalter in den
printf
-Funktionen benutzt.Viele Grüße
-
@hello443 sagte in Ausgabe printf():
Hallo,
ich habe eine Frage zu folgendem Code.
#include <stdio.h> int main() { printf("%f\n", (8/5)/2); printf("%f\n", (float) 5/2); printf("%f\n", (8/5)/2); return 0; }
Die 3. und 5. Zeile sind identisch. Bei der Ausgabe allerdings ist der Wert verschieden. Wie kann das sein, dass bei syntaktisch identischem Code verschiedene Ausgaben erzeugt werden?
8/5 ist 1 (int), 1/2 ist 0 (int). Das Ergebnis ist also ein Integer. Für Integer verwendet man das Format
%d
, nicht%f
. Du hast mit falschem Format undefiniertes Verhalten. Schalte Compilerwarnungen ein!
-
@wob sagte in Ausgabe printf():
Schalte Compilerwarnungen ein!
Und beachte diese und behebe deren Ursache.
-
Falls du MSVC verwendest: Dreh den Warning Level auf 4 (
/W4
), evtl. noch zusätzlich/w44777
mitgeben um Warning C4777 zu aktivieren.Falls du GCC oder Clang verwendest: kompiliere mit mindestens
-Wall -Wextra
.
-
default argument promotions
-
Ich habe einen Stackoverflow Thread eröffnet mit diesem Thema. Jemand schrieb die Erklärung für das undefinierte Verhalten. Darum ging es mir auch. Ich wusste es und habe mit Absicht compiler warnings induziert, weil ich wissen wollte, wie die specifier in
printf()
mit verschiedenen Konstanten unterschiedlichen Datentyps umgehen. Der Grund liegt auf Hardware ebene, da die Register für Ganzzahl- und Fließkommazahlarithmetik unterschiedlich sind.https://stackoverflow.com/questions/74331197/printf-output-c-programming-can-anybody-explain-output
-
@hello443 Ein
int
hat durchaus eine andere Bitbreite als eindouble
Derzeit sind es oft 4 Byte und 8 Byte, die dann auch (nur) anprintf
übergeben werden.Wenn aber nur 4 Byte übergeben werden, aber 8 Byte gelesen werden, steht da noch Müll vom letzten mal.
Dem C-Standard ist die genaue Realisierung aber egal, darum ist es UB und die SO-Begründung nur ein möglicher Spezialfall für einen CPU/Compiler-Typ
Und ja, an
printf
wirddouble
übergeben, auch wenn du da explizit auffloat
castest
-
da is nix undefiniert
-
Doch,
%f
erwartet eindouble
(oder per Promotion einfloat
), aber keine Ganzzahl (int
,short
, ...), s. Variadic arguments: Default conversions.Und s.a. die Top-Antwort bzgl. dem C-Standard zu
printf
: Why does printf("%f",0); give undefined behavior?N1570 7.21.6.1 paragraph 9:
... If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
-