#include int main() { float a = 1234.5f; printf("%d\n", a); return 0; }
Visualizza uno 0
!! Come è ansible? Qual è il ragionamento?
Ho deliberatamente messo un %d
printf
per studiare il comportamento di printf
.
Questo perché %d
aspetta un int
ma tu hai fornito un float.
Usa %e
/ %f
/ %g
per stampare il float.
Perché viene stampato 0: il numero in virgola mobile viene convertito in double
prima di inviarlo a printf
. Il numero 1234.5 in doppia rappresentazione in little endian è
00 00 00 00 00 4A 93 40
A %d
un numero intero a 32 bit, quindi viene stampato uno zero. (Come test, è ansible printf("%d, %d\n", 1234.5f);
È ansible ottenere l’output 0, 1083394560
)
Per quanto riguarda il motivo per cui il float
viene convertito in double
, dal momento che il prototipo di printf è int printf(const char*, ...)
, dal 6.5.2.2/7,
La notazione di ellissi in un dichiaratore di prototipo di funzione causa l’interruzione della conversione del tipo di argomento dopo l’ultimo parametro dichiarato. Le promozioni degli argomenti predefiniti vengono eseguite sugli argomenti finali.
e dal 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 adouble
. Queste sono chiamate promozioni di argomenti predefinite .
(Grazie Alok per averlo scoperto.)
Tecnicamente parlando non c’è la printf
, ogni libreria implementa la sua, e quindi, il tuo metodo di provare a studiare il comportamento di printf
facendo quello che stai facendo non sarà di grande utilità. Potresti provare a studiare il comportamento di printf
sul tuo sistema, e se è così, dovresti leggere la documentazione e guardare il codice sorgente di printf
se è disponibile per la tua libreria.
Ad esempio, sul mio Macbook, ottengo l’output 1606416304
con il tuo programma.
Detto questo, quando si passa un float
a una funzione variadica, il float
viene passato come un double
. Quindi, il tuo programma equivale ad aver dichiarato un double
.
Per esaminare i byte di un double
, puoi vedere questa risposta a una domanda recente qui su SO.
Facciamolo:
#include int main(void) { double a = 1234.5f; unsigned char *p = (unsigned char *)&a; size_t i; printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int)); for (i=0; i < sizeof a; ++i) printf("%02x ", p[i]); putchar('\n'); return 0; }
Quando eseguo il programma di cui sopra, ottengo:
size of double: 8, int: 4 00 00 00 00 00 4a 93 40
Quindi, i primi quattro byte del double
si sono rivelati 0, il che potrebbe essere il motivo per cui hai ottenuto 0
come risultato della tua chiamata printf
.
Per risultati più interessanti, possiamo modificare un po 'il programma:
#include int main(void) { double a = 1234.5f; int b = 42; printf("%d %d\n", a, b); return 0; }
Quando eseguo il programma sopra riportato sul mio Macbook, ottengo:
42 1606416384
Con lo stesso programma su una macchina Linux, ottengo:
0 1083394560
Lo specificatore %d
dice a printf
di aspettarsi un intero. Quindi i primi quattro (o due, in base alla piattaforma), i byte del float sono interpretati come un numero intero. Se capita di essere zero, viene stampato uno zero
La rappresentazione binaria di 1234.5 è qualcosa di simile
1.00110100101 * 2^10 (exponent is decimal ...)
Con un compilatore C che rappresenta float
effettivamente come IEEE754 double values, i byte sarebbero (se non ho fatto alcun errore)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
Su un sistema Intel (x86) con poca endianess (ovvero il byte meno significativo che viene prima), questa sequenza di byte viene invertita in modo che i primi quattro byte siano zero. Cioè, che printf
stampa …
Vedi questo articolo di Wikipedia per la rappresentazione in virgola mobile secondo IEEE754.
È a causa della rappresentazione di un float in binario. La conversione in un numero lo lascia con 0.
Perché hai invocato un comportamento indefinito: hai violato il contratto del metodo printf () mentendo ai suoi tipi di parametro, quindi il compilatore è libero di fare tutto ciò che desidera. Potrebbe rendere il programma in uscita “dksjalk è un ninnyhead !!!” e tecnicamente sarebbe ancora giusto.
Il motivo è che printf()
è una funzione piuttosto stupida. Non controlla affatto i tipi. Se dici che il primo argomento è un int
(e questo è ciò che stai dicendo con %d
), ti crede e richiede solo i byte necessari per un int
. In questo caso, se la tua macchina usa quattro byte int
e otto byte double
(il float
viene convertito in double
in printf()
), i primi quattro byte di a
saranno solo zero, e questo verrà stampato.
Non converte automaticamente float in intero. Perché entrambi hanno diversi formati di archiviazione. Quindi, se vuoi convertire, usa (int) typecasting.
#include int main() { float a = 1234.5f; printf("%d\n", (int)a); return 0; }
Poiché lo hai codificato anche con C ++, questo codice esegue la conversione come probabilmente ti aspetti:
#include int main() { float a = 1234.5f; std::cout << a << " " << (int)a << "\n"; return 0; }
Produzione:
1234.5 1234
%d
è decimale
%f
è float
vedere più di questi qui .
Stai ottenendo 0 perché i float e gli interi sono rappresentati in modo diverso.
È sufficiente utilizzare l’identificatore di formato appropriato (% d,% f,% s, ecc.) Con il tipo di dati pertinente (int, float, stringa, ecc.).
Vuoi% f non% d
hey ha dovuto stampare qualcosa così ha stampato uno 0. Ricorda in C 0 è tutto il resto!
Non è un numero intero. Prova a usare %f
.