Specificatore di formato corretto per il doppio in printf

Qual è l’identificatore di formato corretto per double in printf? È %f o è %lf ? Credo che sia %f , ma non ne sono sicuro.

Codice di esempio

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

"%f" è il formato (o almeno uno) corretto per un doppio. Non esiste un formato per un float , perché se si tenta di passare un float a printf , verrà promosso a double prima che printf riceva 1 . "%lf" è anche accettabile secondo lo standard corrente – la l è specificata come priva di effetto se seguita dallo specificatore di conversione f (tra gli altri).

Si noti che questo è un punto in cui le stringhe di formato printf differiscono sostanzialmente dalle stringhe di formato scanf (e fscanf , ecc.). Per l’output, stai passando un valore , che verrà promosso da float a double quando viene passato come parametro variadic. Per l’input stai passando un puntatore , che non è promosso, quindi devi dire a scanf se vuoi leggere un float o un double , quindi per scanf , %f significa che vuoi leggere un float e %lf significa che vuoi per leggere un double (e, per quello che vale, per un long double , si usa %Lf per printf o scanf ).


1. C99, §6.5.2.2 / 6: “Se l’espressione che denota la funzione chiamata ha un tipo che non include un prototipo, le promozioni intere vengono eseguite su ogni argomento e gli argomenti che hanno il tipo float vengono promossi a doppio. Queste sono chiamate promozioni di argomenti predefinite. “ In C ++ la formulazione è un po ‘diversa (ad esempio, non usa la parola “prototipo”) ma l’effetto è lo stesso: tutti i parametri variadici subiscono le promozioni predefinite prima che vengano ricevute dalla funzione.

Dato lo standard C99 (ovvero 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 apportate alla precedente edizione includono:

  • %lf specificatore di conversione consentito in printf

7.19.6.1 La funzione fprintf

7 I modificatori di lunghezza e i loro significati sono:

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

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

Le stesse regole specificate per fprintf applicano a funzioni printf , sprintf e simili.

7.19.6.2 La funzione fscanf

11 I modificatori di lunghezza e i loro significati sono:

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

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

12 Gli specificatori di conversione e i loro significati sono: a, e, f, g Corrisponde a un numero a virgola mobile con firma opzionale, (…)

14 Anche gli specificatori di conversione A, E, F, G e X sono validi e si comportano come, rispettivamente, a, e, f, g e x.

Per fprintf breve, per fprintf sono specificati i seguenti specificatori e tipi corrispondenti:

  • %f -> doppio
  • %Lf -> long double.

e per fscanf è:

  • %f -> float
  • %lf -> double
  • %Lf -> long double.

Può essere %f , %g o %e seconda di come si desidera che il numero sia formattato. Vedi qui per maggiori dettagli. Il modificatore l è richiesto in scanf con double , ma non in printf .

Il formato printf corretto per il double è %lf , esattamente come lo hai usato. Non c’è niente di sbagliato nel tuo codice.

Formato %lf in printf non era supportato nelle vecchie versioni (pre-C99) del linguaggio C, che creava incoerenze superficiali tra gli specificatori di formato per il double in printf e scanf . Quella incoerenza superficiale è stata fissata in C99.

Quindi nel moderno C ha perfettamente senso preferire usare %f con float , %lf con double e %Lf con long double coerentemente sia in printf che scanf .

%Lf (nota la maiuscola L ) è l’ identificatore di formato per i doppi lunghi .

Per i doubles semplici, verranno doubles sia %e , %E , %f , %g che %G

Per il doppio puoi semplicemente usare %lf o puoi utilizzare uno dei seguenti elementi come preferisci

%e o %E per i valori in formato esponenziale

%g o %G per la notazione normale o esponenziale, a seconda di quale sia più appropriato per la sua grandezza.

Leggi di più qui Elenco di tutti gli specificatori di formato in C