Poprawny specyfikator formatu dla double w printf

480

Jaki jest właściwy specyfikator formatu doublew printf? Czy to %fjest czy jest %lf? Wierzę, że tak %f, ale nie jestem pewien.

Próbka kodu

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}
Lampart
źródło
19
Jeśli utkniesz w bibliotece C89, "%lf"jest niezdefiniowany; w bibliotekach C99 i C11 jest zdefiniowany jako taki sam jak "%f".
pmg
1
Twój wariant jest tak poprawny, jak to tylko możliwe. %lfjest poprawnym specyfikatorem formatu dla double. Ale stało się tak w C99. Wcześniej trzeba było użyć %f.
AN

Odpowiedzi:

624

"%f"jest (lub przynajmniej jednym) poprawnym formatem dla podwójnego. Jest to nie dla formatu float, ponieważ jeśli spróbujesz przejść floatdo printf, to będzie promowany na doublezanim printfotrzyma go 1 . "%lf"jest również akceptowalny w ramach obecnego standardu - lokreśla się, że nie wywołuje żadnego efektu, jeśli następuje po nim specyfikator fkonwersji (między innymi).

Zauważ, że jest to jedno miejsce, w którym printfciągi formatujące różnią się zasadniczo od scanf(i fscanfitp.) Ciągów formatujących. Jako wynik podajesz wartość , która będzie promowana od floatdo, doublegdy zostanie przekazana jako parametr variadic. Dla wejścia jesteś przechodzącą wskaźnik , który nie jest promowane, więc trzeba powiedzieć scanf, czy chcesz czytać floatlub double, tak aby scanf, %foznacza, że chcesz czytać floati %lfoznacza, że chcesz czytać double(i za to, co warto long doubleużyć %Lfdla jednego printflub scanf).


1. C99, §6.5.2.2 / 6: „Jeśli wyrażenie oznaczające wywoływaną funkcję ma typ, który nie zawiera prototypu, promocje na liczby całkowite są wykonywane dla każdego argumentu, a argumenty, które mają typ float, są podwyższane dwukrotnie. Są to tak zwane domyślne promocje argumentów. ” W C ++ sformułowanie jest nieco inne (np. Nie używa słowa „prototyp”), ale efekt jest taki sam: wszystkie parametry variadic podlegają domyślnej promocji, zanim zostaną odebrane przez funkcję.

Jerry Coffin
źródło
8
Zauważ, że g++odrzuca %lfpodczas kompilacji z -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan
2
@kynan: Jeśli tak (przynajmniej przy założeniu aktualnej wersji g ++), to błąd w g ++. W przypadku C89 / 90 i C ++ 98/03 zezwalanie lbyło rozszerzeniem. Standardy C99 / 11 i C ++ 11 wymagają implementacji, aby na to pozwolić.
Jerry Coffin
1
Co ciekawe, scanf robi Kupię doubles reprezentowane przez %lf: narzeka, że oczekuje float *i okazało double *się po prostu %f.
Eric Dand
1
@JerryCoffin g ++ nadal domyślnie pracuje w trybie g ++ 98
MM
5
@EricDand to dlatego, że scanftrwa odnośniki do miejsca przechowywania, co czyta, więc potrzeby , aby wiedzieć, jak duża przestrzeń jest spiczasty, na to, podczas gdy printftrwa same wartości i „promocji argumentów domyślnych” oznacza zarówno skończyć jako doubles, więc ljest zasadniczo opcjonalne.
TripeHound,
63

Biorąc pod uwagę standard C99 (mianowicie szkic N1256 ), reguły zależą od rodzaju funkcji: fprintf (printf, sprintf, ...) lub scanf.

Oto wyodrębnione części:

Przedmowa

To drugie wydanie anuluje i zastępuje pierwsze wydanie, ISO / IEC 9899: 1990, zmienione i poprawione przez ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 i ISO / IEC 9899 / COR2: 1996. Główne zmiany w stosunku do poprzedniej edycji to:

  • %lf specyfikator konwersji dozwolony w printf

7.19.6.1 fprintfFunkcja

7 Modyfikatory długości i ich znaczenie to:

l (ell) Określa, że ​​(...) nie ma wpływu na następujący specyfikator konwersji a, A, e, E, f, F, g lub G.

L Określa, że ​​następujący długi specyfikator konwersji a, A, E, E, f, F, g lub G ma zastosowanie do długiego podwójnego argumentu.

Te same zasady określone dla fprintfubiegać printf, sprintfa podobne funkcje.

7.19.6.2 fscanfFunkcja

11 Modyfikatory długości i ich znaczenie to:

l (ell) Określa, że ​​(...) następujące argumenty konwersji a, A, e, E, f, F, g lub G mają zastosowanie do argumentu ze wskaźnikiem typu, który należy podwoić;

L Określa, że ​​następujący argument specyfikujący konwersję a, A, E, E, f, F, g lub G ma zastosowanie do argumentu ze wskaźnikiem typu na długim podwójnym.

12 Specyfikatorami konwersji i ich znaczeniami są: a, e, f, g Dopasowuje opcjonalnie podpisaną liczbę zmiennoprzecinkową, (...)

14 Specyfikatory konwersji A, E, F, G i X są również ważne i zachowują się tak samo, jak odpowiednio a, e, f, g i x.

Krótko mówiąc, fprintfokreślono następujące specyfikatory i odpowiadające im typy:

  • %f -> podwójne
  • %Lf -> długi podwójny.

a do fscanftego jest:

  • %f -> pływak
  • %lf -> podwójne
  • %Lf -> długi podwójny.
mloskot
źródło
25

To może być %f, %glub %ew zależności od tego, jak chcesz numer do sformatowania. Zobacz tutaj po więcej szczegółów. lModyfikator jest wymagana scanfz double, ale nie printf.

vitaut
źródło
1
-1: lmodyfikator (małe litery) dotyczy typów całkowitych ( cplusplus.com/reference/clibrary/cstdio/printf ) i Ljest przeznaczony dla typów zmiennoprzecinkowych. Dodatkowo Lmodyfikator oczekuje, a long doublenie zwykłego double.
user470379,
10
user470379: Więc gdzie jest sprzeczność z moją odpowiedzią? Nie powiedziałem, że lnie jest wymagane printfdla double.
vitaut
15

Format %lfjest idealnie poprawnym printfformatem doubledokładnie tak, jak go używałeś. W twoim kodzie nie ma nic złego.

Format %lfw printfnie był wspierany w starych (pre-C99) wersji języka C, który stworzył „powierzchowne” niespójność pomiędzy formatem specyfikatorami na doublew printfi scanf. Ta powierzchowna niespójność została naprawiona w C99.

Nie są wymagane do korzystania %lfz doublew printf. Możesz również użyć %f, jeśli tak wolisz ( %lfi %fmasz równoważne w printf). Ale we współczesnym C sensowne jest preferowanie używania %fz float, %lfz doublei %Lfz long double, konsekwentnie w obu printfi scanf.

Mrówka
źródło
Z scanf(), "%f", "%lf"dopasowywania float *, double *, a nie float, doublejak sugeruje ostatniej linii.
chux - Przywróć Monikę
9

%Lf(uwaga na kapitał L) jest specyfikatorem formatu dla długich podwójnych .

Dla zwykłego doubles, albo %e, %E, %f, %glub %Gzrobi.

Frédéric Hamidi
źródło
Jaka jest różnica między %gi %G?
yanpas
@yanpas, odpowiednio małe / duże litery dla symbolu wykładnika.
Frédéric Hamidi
przepraszam,% g i% G generują symbol E. Ponadto
wysyłają