Identificatore di formato corretto per double in printf


482

Qual è l'identificatore di formato corretto per doublein printf? È %fo è %lf? Credo di si %f, ma non ne sono sicuro.

Esempio di codice

#include <stdio.h>

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

19
Se sei bloccato con una libreria C89, "%lf"non è definito; nelle librerie C99 e C11 è definito come "%f".
pm

1
La tua variante è più corretta che mai. %lfè l'identificatore di formato corretto per double. Ma è diventato così nel C99. Prima si doveva usare %f.
AnT

Risposte:


626

"%f"è il (o almeno uno) formato corretto per un doppio. Non esiste un formato per a float, perché se si tenta di passare un floata printf, verrà promosso doubleprima di printfriceverlo 1 . "%lf"è accettabile anche in base allo standard attuale - lviene specificato come non efficace se seguito dallo fspecificatore di conversione (tra gli altri).

Si noti che questo è un punto in cui le printfstringhe di formato differiscono sostanzialmente dalle stringhe di formato scanf(e fscanf, ecc.). Per l'output, stai passando un valore , che verrà promosso da floata doublequando passato come parametro variadico. Per l'input stai passando un puntatore , che non è promosso, quindi devi dire scanfse vuoi leggere a floato a double, quindi per scanf, %fsignifica che vuoi leggere un floate %lfsignifica che vuoi leggere un double(e, per quello che è vale la pena, per a long double, che usi %Lfper printfo scanf).


1. C99, §6.5.2.2 / 6: "Se l'espressione che indica la funzione chiamata ha un tipo che non include un prototipo, le promozioni dei numeri interi vengono eseguite su ogni argomento e gli argomenti che hanno il tipo float vengono promossi al doppio. Queste sono chiamate promozioni dell'argomento predefinito ". In C ++ la formulazione è in qualche modo diversa (ad esempio, non usa la parola "prototipo") ma l'effetto è lo stesso: tutti i parametri variadici vengono sottoposti a promozioni predefinite prima di essere ricevuti dalla funzione.


8
Si noti che g++rifiuta %lfdurante la compilazione con -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@kynan: In questo caso (supponiamo che si tratti di una versione corrente di g ++), è un bug in g ++. Per C89 / 90 e C ++ 98/03, consentire lera un'estensione. Gli standard C99 / 11 e C ++ 11 richiedono l'implementazione per consentirlo.
Jerry Coffin,

1
Curiosamente, scanf fa mancanza doubles rappresentato da %lf: si lamenta che si attendeva float *e ha trovato double *con appena %f.
Eric Dand,

1
@JerryCoffin g ++ è ancora predefinito in modalità g ++ 98
MM

5
@EricDand Questo perché scanfprende indicazioni su dove archiviare ciò che legge, quindi deve sapere quanto è grande lo spazio puntato, mentre printfprende i valori stessi e "promozioni con argomenti predefiniti" significa che entrambi finiscono come doubles, quindi lè essenzialmente facoltativo.
TripeHound,

63

Dato lo standard C99 (vale a dire la bozza N1256 ), le regole dipendono dal tipo di funzione: fprintf (printf, sprintf, ...) o scanf.

Ecco le parti rilevanti estratte:

Prefazione

Questa seconda edizione annulla e sostituisce la prima edizione, ISO / IEC 9899: 1990, come modificata e corretta da ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 e ISO / IEC 9899 / COR2: 1996. Le principali modifiche rispetto all'edizione precedente includono:

  • %lf identificatore di conversione consentito in printf

7.19.6.1 La fprintffunzione

7 I modificatori di lunghezza e i loro significati sono:

l (ell) Specifica che (...) non ha alcun effetto sul seguente identificatore di conversione a, A, e, E, f, F, g o G.

L Specifica che un seguente identificatore di conversione a, A, e, E, f, F, g o G si applica a un argomento doppio lungo.

Le stesse regole specificate per fprintfdomanda per printf, sprintfe funzioni simili.

7.19.6.2 La fscanffunzione

11 I modificatori di lunghezza e i loro significati sono:

l (ell) Specifica che (...) che un seguente identificatore di conversione a, A, e, E, f, F, g o G si applica a un argomento con puntatore di tipo doppio;

L Specifica che un seguente identificatore di conversione a, A, e, E, f, F, g o G si applica a un argomento con puntatore di tipo a doppio lungo.

12 Gli identificatori di conversione e i loro significati sono: a, e, f, g Corrisponde a un numero in virgola mobile con segno facoltativo, (...)

14 Anche gli identificatori di conversione A, E, F, G e X sono validi e si comportano allo stesso modo rispettivamente di a, e, f, g e x.

Per farla breve, fprintfvengono specificati i seguenti identificatori e tipi corrispondenti:

  • %f -> doppio
  • %Lf -> doppio lungo.

e fscanfperché è:

  • %f -> galleggiante
  • %lf -> doppio
  • %Lf -> doppio lungo.

25

Può essere %f, %go %eseconda di come si desidera che il numero da formattare. Vedi qui per maggiori dettagli. Il lmodificatore è richiesto in scanfcon double, ma non in printf.


1
-1: il lmodificatore (minuscolo) è per tipi interi ( cplusplus.com/reference/clibrary/cstdio/printf ) ed Lè per tipi a virgola mobile. Inoltre, il Lmodificatore prevede un long double, non un semplice double.
user470379

10
user470379: Allora dov'è la contraddizione con la mia risposta? Non ho detto che lnon è richiesto printfper double.
vitaut

16

Il formato %lfè un printfformato perfettamente corretto per double, esattamente come lo hai usato. Non c'è niente di sbagliato nel tuo codice.

Il formato %lfin printfnon era supportato nelle versioni precedenti (pre-C99) del linguaggio C, che creavano "incoerenze" superficiali tra gli identificatori di formato per doublein printfe scanf. Questa incoerenza superficiale è stata risolta nel C99.

Non è necessario utilizzare %lfcon doublein printf. Puoi usare %fanche, se preferisci ( %lfe %fsei equivalente in printf). Ma nella C moderna ha perfettamente senso preferire l'uso %fcon float, %lfcon doublee %Lfcon long double, costantemente in entrambi printfe scanf.


Con scanf(), "%f", "%lf"abbinare un float *, double *, non float, doublecome implica l'ultima riga.
chux - Ripristina Monica l'

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.