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.