Perché scanf () ha bisogno di "% lf" per i doppi, quando printf () va bene con solo "% f"?


179

Perché è scanf()necessario l"in %lf" quando si legge a double, quando è printf()possibile utilizzare " %f" indipendentemente dal fatto che il suo argomento sia a doubleo a float?

Codice di esempio:

double d;
scanf("%lf", &d);
printf("%f", d);

1
Non capisco cosa intendi per PUNTATORE qui. In scanf passiamo solo l'indirizzo variabile (es.), Quindi dov'è il puntatore

7
@deetchanya In C, quando "prendi l'indirizzo di" una variabile con l' &operatore unario , il risultato di quell'operazione è un puntatore alla posizione di memorizzazione della variabile in memoria. È quel puntatore a cui viene passato scanf.
zwol,

questo è un altro post riguardo a questa stackoverflow.com/questions/9291348/...
vimalpt

Risposte:


207

Perché C promuoverà i float a doppi per funzioni che accettano argomenti variabili. I puntatori non sono promossi a nulla, quindi dovresti usare %lf, %lgo %le(o %lain C99) per leggere in doppio.


26

Da С99 la corrispondenza tra identificatori di formato e tipi di argomenti in virgola mobile in C è coerente tra printfe scanf. È

  • %f per float
  • %lf per double
  • %Lf per long double

Accade così che quando argomenti di tipo floatvengono passati come parametri variadici, tali argomenti vengono convertiti implicitamente in tipo double. Questo è il motivo per cui in printfidentificatori di formato %fe %lfsono equivalenti ed intercambiabili. In printfpuoi "cross-use" %lfcon floato %fcon double.

Ma non c'è motivo di farlo in pratica. Non usare %fper printfargomenti di tipo double. È un'abitudine diffusa nata nel C89 / 90 volte, ma è una cattiva abitudine. Utilizzare %lfin printfper doublee mantenere %friservato per gli floatargomenti.


1
Direi che usare %fin printf è una buona abitudine perché il tuo codice funziona sempre, mentre l'utilizzo %lfpotrebbe non riuscire se il compilatore non ha una libreria conforme a C99. Sfortunatamente quella situazione accade nella realtà.
MM

Da С99 la corrispondenza tra identificatori di formato e tipi di argomenti in virgola mobile in C è coerente tra printfe scanf. Si noti che ciò non implica che l'utilizzo dello stesso identificatore di formato significhi che i dati scritti da a [f]printf()possono essere letti da [f]scanf(). In generale, utilizzando lo stesso identificatore di formato per scanf()che è stato utilizzato da printf()sarà non leggere correttamente i dati. Ad esempio, il riempimento dello spazio che può essere inserito da un prinf()identificatore di "%d"formato verrà ignorato dallo stesso identificatore di "%d"formato in una scanf()chiamata.
Andrew Henle,

16

scanfha bisogno di conoscere la dimensione dei dati puntati da &driempire correttamente, mentre le funzioni variadiche promuovono i float a raddoppiare (non del tutto sicuro del perché), quindi printfottiene sempre a double.


1
Una funzione variadica è molto fragile, perché deve essere in grado di conoscere il tipo esatto e le dimensioni di tutti i parametri passati ad essa, e non può imporlo al momento della compilazione. Se una variabile è del tipo sbagliato, verrà letto il valore sbagliato; se ha dimensioni errate, anche tutte le variabili successive verranno interpretate erroneamente. Se si potessero passare due diverse dimensioni di galleggiante, ciò causerebbe tutti i tipi di problemi cattivi e facili da perdere.
mwfearnley,

7

Perché altrimenti scanf penserà di passare un puntatore a un float di dimensioni inferiori rispetto a un doppio e restituirà un valore errato.


2

L'uso di un valore float o double in un'espressione C comporterà comunque un valore double, quindi printf non può distinguere. Considerando che un puntatore a un doppio deve essere esplicitamente segnalato a scanf come distinto da un puntatore a float, perché ciò che conta il puntatore è ciò che conta.


5
float viene convertito in doppio in questo caso perché gli argomenti fanno parte di un elenco di argomenti a lunghezza variabile, i float non vengono sempre convertiti in doppi in C.
Robert Gamble,

1
Nelle versioni pre-standard del linguaggio C i floatvalori venivano automaticamente promossi doublein espressioni. Quella regola è stata abbandonata nello standard C. Generalmente, floatnon viene promossa doublenelle espressioni. Viene promosso solo doublequando passato come argomento variadico, che è ciò che accade in questo caso.
Il
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.