2011-09-20 6 views
14

Sto cercando di imparare C leggendo C Programming Language, 2nd Edition. Ho una certa esperienza di programmazione, ma non con C.Cosa succede a una variabile mobile quando% d è usato in una printf?

Sono attualmente nel Capitolo 1. Ho il seguente codice:


float f; 
    for (f = 0.0; f <= 3; f += 1.1) 
     printf("A: %3f B: %6.2f\n", f, f + 0.15); 

esso stampa l'output:

A: 0.000000 B: 0.15 
A: 1.100000 B: 1.25 
A: 2.200000 B: 2.35 

Sembra a posto


Ora cambiare il printf come segue:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

La nuova uscita è

A: 0 B: 0.00 
A: -1610612736 B: 0.00 
A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00 

cosa sta succedendo qui? Mi aspetto che il float sia convertito in int perché ho usato% d ma non è quello che è successo. Inoltre, perché il valore B è andato storto? Cosa è successo a f qui?

+2

Non hai chiesto di convertirlo in int, hai detto che ** era ** un int! Immondizia, spazzatura. –

risposta

15

Quando hai chiamato:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

C converte automaticamente i valori float a double (è una conversione standard eseguita quando si chiama una funzione che accetta argomenti variabili, ad esempio int printf(const char *fmt, ...);). Per ragioni, assumeremo che sizeof(int) è 4 e sizeof(double) è 8 (ci sono eccezioni, ma sono poche e distanti tra loro).

La chiamata, quindi, ha spostato un puntatore sulla pila, più un doppio di 8 byte per f e un altro doppio di 8 byte per f + 0.15. Quando elabora la stringa di formato, lo %d indica a printf() che è stato inserito uno stack di 4 byte int nello stack dopo la stringa di formato. Poiché non è quello che hai fatto, hai invocato un comportamento indefinito; qualunque cosa accada, è OK secondo lo standard C.

Tuttavia, l'implementazione più probabile legge tranquillamente 4 byte e li stampa come se fossero uno int (si fida di dirgli la verità). Quindi viene visualizzato il formato %6.2f; leggerà 8 byte dalla pila come double. Esiste una possibilità esterna che ciò provocherebbe un errore di memoria per l'accesso disallineato (richiederebbe una macchina a 64 bit con il requisito che double sia allineato su un limite di 8 byte, come uno SPARC), o leggerà 4 byte da f e 4 byte da f + 0.15, mettendoli insieme per creare un valore piuttosto inaspettato double - come mostra l'esempio.

+0

ottima risposta, quindi puoi 'printf (" A:% d% d B:% 6.2 ", ...' e sbagliare A vals ma B non sarà influenzato –

+1

Sotto un gran numero di ipotesi abbastanza plausibili, sì Il comportamento è rigorosamente indefinito, ma in pratica sì. –

8

Printf tratterà la memoria che si punta come a cui si dice. Non ci sono conversioni in corso. Tratta la memoria che rappresenta il float come un int. Perché i due sono memorizzati in modo diverso, si ottiene quello che è essenzialmente un numero casuale.

Se si desidera attivare il galleggiante come un intero, si dovrebbe lanci prima:

printf("A: %3d B: %6.2f\n", (int)f, f + 0.15); 
+1

Ok, questo ha senso. Quindi il valore di f è cambiato perché non l'ho lanciato come int? In caso contrario, la seconda parte di printf utilizza% 6.2f, quindi dovrebbe avere almeno il valore corretto? – Gollum

Problemi correlati