2015-01-22 7 views
19

aus einer früheren question:Warum printf() ein Float zu einem Double hochlädt?

Wenn Sie ein float zu printf passieren versuchen, es zu double vor printf gefördert werden empfängt es

printf() eine variadische Funktion richtig ist? Also fördert eine Variadic-Funktion ein float Argument zu einem double vor der Übergabe?

+5

Ja, über die "default argument promotions". –

+2

Ähnlich wird 'char' zu' int' befördert, also 'char c = 127; printf ("% d", c); 'funktioniert auch richtig. –

+1

Würdest du lieber ein Double zu einem Float _demote_? Würden Sie lieber die Komplexität hinzufügen, wenn jeder Typ unabhängig von anderen eng verwandten Typen ist? Die Beförderung von Floats scheint mir die Lösung des gesunden Menschenverstandes zu sein. – abelenky

Antwort

20

Ja, float Argumente zu variadic Funktion werden doppelt gefördert.

Der draft C99 standard Abschnitt 6.5.2.2 Funktionsaufrufe sagt:

[...] und Argumente, dass Typ float haben, werden gefördert zu verdoppeln. Diese sind das Standardargument genannt Promotions [...]

vom draft C++ standard Abschnitt 5.2.2 Funktionsaufruf:.

[...] ein Gleitkomma-Typ, der auf den Floating-Point unterliegen promotion (4.6), der Wert des Arguments wird vor dem Aufruf in den promoteten Typ konvertiert. [...]

und Abschnitt 4.6:

A prvalue vom Typ float können doppelt auf einen prvalue vom Typ umgewandelt werden. Der Wert ist unverändert

cppreference die default conversions für Variadische Funktion in C umfasst ++ gut:

  • std :: nullptr_t umgewandelt wird void *
  • Schwimmers Argumente als zu verdoppeln umgewandelt in floating -point promotion
  • Bool-, Char-, Short- und Unscoped-Enumerationen werden in Int-Typen oder breitere Integer-Typen konvertiert, wie in Integer-Werbungen

Wir in C und vermutlich in C sehen ++ wurde diese Umwandlung um mit K & RC, von Rationale for International Standard—Programming Languages—C (Hervorhebung von mir) für die Kompatibilität gehalten:

Für die Kompatibilität mit der bisherigen Praxis, Alle Argumentpromotionen erfolgen wie in beschrieben in K & R in Abwesenheit einer Prototypdeklaration, inklusive der nicht immer wünschenswerten Promotion von float to double.

+0

* Ja, Float-Argumente für Variadic-Funktion werden zu Double befördert. * Nur in Trailing-Argumenten. Bitte beheben Sie dies. – 2501

14

Was die warum Teil der Frage, es ist ganz einfach: die C (und C++) Standards double betrachten die „default“ Typ Gleitkomma zu sein. Nicht float (das ist, was viele von uns Programmierern standardmäßig bei der Verwendung von Gleitkommazahlen).

  1. 3.14 ein double ist
  2. Die Standard-Mathematik-Funktionen übernehmen (wenn Sie einen float wollen, haben Sie einen zusätzlichen Schritt und fügen Sie ein f nehmen bekam):

    Dies kann durch die Beobachtung zu sehen ein double standardmäßig (zum Beispiel nimmt sin() ein double, wenn Sie wollen ein float du hast sinf() verwenden)

Mit diesem scheint es "natürlicher", dass ein float in einem Variadic-Funktionsaufruf zu double heraufgestuft wird, da double der "natürliche" Standard in der Sprache ist.

+2

"Nicht' float' ist das, was viele Programmierer bei der Verwendung von Gleitkommazahlen verwenden. " Ich weiß nicht, wie andere das machen, aber normalerweise nehme ich 'double'.Ich gehe nur auf "float" zurück, wenn es darum geht, e zu speichern. G. viele Messdaten mit einem recht hohen Eigenfehler, die in einer Datei gespeichert werden müssen. – glglgl

+2

Eines meiner großen Bedauern über C ist, dass, wenn 'long double' hinzugefügt wurde, kein Mechanismus enthalten war, um anzugeben, ob eine variadische Funktion erwartet, dass alle Gleitkommawerte in den längsten Typ (' long double') konvertiert werden, spezifischer Typ 'double', oder dass' 'long double'' und' double' anders erwartet werden. IMHO, würde viel Zeit und Portabilität Kopfschmerzen im Laufe der Jahre gespeichert worden, wenn Code hätte gesagt werden können "Konvertieren Sie alle Integer-ish zu diesem Typ und alles float-ish zu diesem Typ". – supercat

11

Weil der (C99 oder C11) Standard so sagt. Siehe answer by 2501.

Es gibt mehrere pragmatische Gründe dafür: Geschichte (erste Implementierungen von C wurden für die Systemprogrammierung verwendet, wo Gleitkommaoperationen keine Rolle spielen), und die Tatsache, dass auf aktuell (Tablet, Desktop, Server ...) Prozessoren, arithmetische Operationen auf double sind etwa so effizient wie float (aber einige billige Mikrocontroller haben keine FPU, oder können nur float per Hardware hinzufügen, und erfordern eine Bibliothek für jede Operation auf double). Endlich denke ich, dass eine solche Regel etwas einfacher calling conventions und ABI s ermöglicht.

Denken Sie an float als eine Art-of short double (was natürlich illegal in C). A float ist vor allem nützlich, wenn Sie Speicher komprimieren müssen (und den Verlust der Genauigkeit leisten können). Siehe auch http://floating-point-gui.de/ für mehr.

+0

Wo sagt C99 oder C11 Standard so? Wirst du bitte ein genaues Zitat aus dem Standard enthalten? – Destructor

+0

Ich bin nicht sicher, dass ich dafür Zeit habe. Oder warte ein paar Tage. –

+0

Ein Float ist auch in aktuellen Mikrocontrollern für eingebettete Systeme nützlich. Nicht unbedingt wegen der Größe, sondern weil es ein paar Controller gibt, die nur FPU-Unterstützung für einfache Genauigkeit haben. – CodeMonkey

13

Bei einem Funktionsprototyp wird der Typ float nur automatisch heraufgestuft , wenn er in nachfolgenden Argumenten verwendet wird. Funktion Drucken verwendet diese:

int printf(const char * restrict format, ...); 

(Zitiert aus: ISO/IEC 9899: 201x 6.5.2.2 Funktionsaufrufe)
6. Die ganze Zahl Promotions auf jedes Argument durchgeführt werden, und die Argumente, haben Typ float werden doppelt gefördert. Diese werden als Standardargument Promotions bezeichnet.
7. Das Standardargument Promotions werden für nachfolgende Argumente ausgeführt.

Verwandte Themen