Korrekter Formatbezeichner für double in printf


482

Wofür ist der richtige Formatbezeichner doublein printf? Ist es %foder ist es %lf? Ich glaube es ist %f, aber ich bin nicht sicher.

Codebeispiel

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}

19
Wenn Sie mit einer C89-Bibliothek "%lf"nicht weiterkommen, ist dies nicht definiert. In C99- und C11-Bibliotheken ist es dasselbe wie "%f".
PMG

1
Ihre Variante ist so korrekt wie nie zuvor. %lfist der richtige Formatbezeichner für double. Aber es wurde so in C99. Vorher musste man verwenden %f.
AnT

Antworten:


626

"%f"ist das (oder mindestens ein) richtige Format für ein Double. Es gibt kein Format für a float, denn wenn Sie versuchen, ein an floatzu übergeben printf, wird es heraufgestuft, doublebevor es printfempfangen wird 1 . "%lf"ist auch nach dem aktuellen Standard akzeptabel - das lwird als wirkungslos angegeben, wenn es funter anderem vom Konvertierungsspezifizierer befolgt wird .

Beachten Sie, dass sich Formatzeichenfolgen an dieser Stelle printferheblich von Formatzeichenfolgen scanf(und fscanfusw.) unterscheiden. Für die Ausgabe übergeben Sie einen Wert , der von floatbis doublehochgeschrieben wird , wenn er als variadischer Parameter übergeben wird. Für die Eingabe vorbei sind Sie einen Zeiger , die nicht gefördert wird, so muss man sagen , scanfob Sie ein lesen möchten floatoder ein double, so für scanf, %fMittel Sie lesen möchten floatund %lfMittel Sie lesen wollen double(und für das, was es ist wert, für a long double, verwenden Sie %Lfentweder printfoder scanf).


1. C99, §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 dem Typ float werden auf double heraufgestuft. Diese werden als Standardargumentwerbung bezeichnet. " In C ++ ist der Wortlaut etwas anders (z. B. wird das Wort "Prototyp" nicht verwendet), aber der Effekt ist der gleiche: Alle variadischen Parameter werden standardmäßig hochgestuft, bevor sie von der Funktion empfangen werden.


8
Beachten Sie, dass g++Spuck %lfbeim Kompilieren mit -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
Kynan

2
@kynan: Wenn ja (zumindest unter der Annahme einer aktuellen Version von g ++), ist das ein Fehler in g ++. Für C89 / 90 und C ++ 98/03 war das Zulassen leine Erweiterung. Die Standards C99 / 11 und C ++ 11 erfordern die Implementierung, um dies zu ermöglichen.
Jerry Coffin

1
Merkwürdigerweise scanf macht Mangel doubles vertreten durch %lf: es beklagt , dass es erwartet , float *und fand double *mit nur %f.
Eric Dand

1
@ JerryCoffin g ++ ist immer noch standardmäßig im g ++ 98-Modus
MM

5
@EricDand Das liegt daran , scanfnimmt Verweise, wo zu speichern , was es liest, so Bedürfnisse zu wissen , wie groß der Raum ist Spitz an ist, während printfdie Werte nimmt sich selbst und „Standardargument Promotions“ bedeuten sowohl Ende als up doubles, so das list im Wesentlichen optional.
TripeHound

63

In Anbetracht des C99- Standards (nämlich des N1256- Entwurfs) hängen die Regeln von der Funktionsart ab: fprintf (printf, sprintf, ...) oder scanf.

Hier werden relevante Teile extrahiert:

Vorwort

Diese zweite Ausgabe storniert und ersetzt die erste Ausgabe, ISO / IEC 9899: 1990, geändert und korrigiert durch ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 und ISO / IEC 9899 / COR2: 1996. Wichtige Änderungen gegenüber der vorherigen Ausgabe sind:

  • %lf Konvertierungsspezifizierer erlaubt in printf

7.19.6.1 Die fprintfFunktion

7 Die Längenmodifikatoren und ihre Bedeutung sind:

l (ell) Gibt an, dass (...) keine Auswirkung auf einen folgenden a-, A-, e-, E-, f-, F-, g- oder G-Konvertierungsspezifizierer hat.

L Gibt an, dass ein Konvertierungsspezifizierer für a, A, e, E, f, F, g oder G für ein langes Doppelargument gilt.

Die gleichen Regeln festgelegt für fprintfbeantragen printf, sprintfund ähnliche Funktionen.

7.19.6.2 Die fscanfFunktion

11 Die Längenmodifikatoren und ihre Bedeutung sind:

l (ell) Gibt an, dass (...) ein nachfolgender Konvertierungsspezifizierer a, A, e, E, f, F, g oder G für ein Argument mit dem Typzeiger auf double gilt;

L Gibt an, dass ein Konvertierungsspezifizierer für a, A, e, E, f, F, g oder G für ein Argument mit dem Typzeiger auf long double gilt.

12 Die Konvertierungsspezifizierer und ihre Bedeutung sind: a, e, f, g Entspricht einer optional signierten Gleitkommazahl, (...)

14 Die Umrechnungsspezifizierer A, E, F, G und X sind ebenfalls gültig und verhalten sich wie a, e, f, g und x.

Kurz gesagt, für fprintfdie folgenden Spezifizierer und entsprechenden Typen werden angegeben:

  • %f -> doppelt
  • %Lf -> langes Doppel.

und dafür fscanfist:

  • %f -> schweben
  • %lf -> doppelt
  • %Lf -> langes Doppel.

25

Es kann sein %f, %goder %eje nachdem , wie Sie wollen , dass die Zahl formatiert werden. Sehen Sie hier für weitere Details. Der lModifikator wird in scanfmit double, aber nicht in benötigt printf.


1
Der lModifikator -1: (Kleinbuchstaben) gilt für Ganzzahltypen ( cplusplus.com/reference/clibrary/cstdio/printf ) und Lfür Gleitkommatypen. Außerdem Lerwartet der Modifikator eine long double, keine Ebene double.
user470379

10
user470379: Wo ist also der Widerspruch zu meiner Antwort? Haben Sie nicht , sagte ich , dass lnicht in erforderlich ist printffür double.
Vitaut

16

Format %lfist ein perfekt korrektes printfFormat für doublegenau das, was Sie verwendet haben. Es ist nichts falsch mit Ihrem Code.

Format %lfin printfwurde in alten (vor C99) Versionen der C-Sprache nicht unterstützt, was zu oberflächlichen "Inkonsistenzen" zwischen Formatspezifizierern für doublein printfund führte scanf. Diese oberflächliche Inkonsistenz wurde in C99 behoben.

Sie müssen nicht %lfmit doublein verwenden printf. Sie können auch verwenden %f, wenn Sie dies bevorzugen ( %lfund %fin gleichwertig sind printf). Aber im modernen C ist es absolut sinnvoll, es vorzuziehen, %fmit float, %lfmit doubleund %Lfmit long doublekonsequent in beiden printfund zu verwenden scanf.


Mit scanf(), "%f", "%lf"paßt ein float *, double *, nicht float, doublewie sie in der letzten Zeile angedeutet.
chux

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.