2013-07-07 9 views
5
printf("line 5: %f\n",98); //output is 0.000000 
printf("line 6: %f\n",98.98); //output is 98.980000 
printf("line 5: %f\n",98);//though same as first printf statement but output is 98.979980 

Anche se la prima e l'ultima istruzione printf sono esattamente uguali, ma la loro uscita è diversa. Perché?Perché la prima e la terza stampa funzionano in modo così diverso?

a causa di un int è passato a printf quando si aspetta float, ecco perché ha funzionato strano. Ma il mio punto è il motivo per cui nell'ultima stampa, invece di stampare qualche valore di spazzatura o 0, sta usando il valore della seconda istruzione printf e questo è ciò che viene stampato.

+0

http://codepad.org/P6wolXsM –

+2

@hbrock, il compilatore non ha importanza. Il codice OP causa un comportamento indefinito. Questa domanda è un duplicato centinaia di volte. –

+0

perché un int è passato a printf quando si aspetta float, ecco perchè ha funzionato in modo strano. Ma il mio punto è il motivo per cui nell'ultima stampa, invece di stampare qualche valore di spazzatura o 0, sta usando il valore della seconda istruzione printf e questo è ciò che viene stampato. –

risposta

5

Come altri hanno già detto, il superamento di un int per printf quando è in attesa di un double cause comportamento indefinito, e tutto può succedere. Potresti essere interessato al motivo perché il programma stampa il 98.979980 sulla terza riga e non un numero casuale.

Gli argomenti vengono passati a printf nello stack. Quando la riga 2 passa 98.98 a printf, viene inserito in pila, con la parte meno significativa del numero precedente.

Quindi torna printf e nella terza riga viene richiamato, ora con 98 inserito nello stack. Sulla tua architettura il tipo int sembra essere a 32 bit; metà delle dimensioni del tipo double, quindi questo sovrascrive solo la metà inferiore di 98.98 che era in pila in precedenza. La metà superiore di 98,98 è ancora in pila.

Ora la terza chiamata a printf legge uno double dallo stack. La metà più significativa di ciò che legge proviene dallo 98.98 che era in pila in precedenza e la metà meno significativa viene dalla rappresentazione binaria di 98; questo è il motivo per cui il risultato è così vicino allo 98.98. Poiché 98 è un numero così piccolo, i suoi bit più significativi saranno 0 e impostando la metà meno significativa di 98.98 su zeri per lo più, si ottiene un numero inferiore.

Se la riga 3 utilizza un numero con più bit impostati su 1, si ottiene un risultato superiore a 98.98. Ad esempio, la rappresentazione binaria di -1 ha tutti i bit a 1, e si ottiene:

printf("line 2: %f\n", 98.98); # 98.98 
printf("line 3: %f\n", -1); # 98.980042 

Se il compilatore usato 64 int bit o passati double s con la parte più significativa prima, o utilizzata una registrarsi al posto dello stack per passare i parametri, otterresti risultati molto diversi.

4

Perché il programma invoca il comportamento non definito .98 è di tipo int, ma %f prevede uno float (o double, a causa delle regole di promozione predefinite).

Quindi, dal momento che printf() dispone di UB quando i tipi degli specificatori di conversione e i tipi effettivi non corrispondono, non c'è una spiegazione ragionevole per qualsiasi cosa faccia.

2

Questo perché %f richiede un doppio parametro. Dare un int è un comportamento non definito.

ISO/IEC 9899:1999, §7.19.6.1, 9:

Se uno degli argomenti non è del tipo corretto per la specifica di conversione corrispondente, il comportamento è indefinito.

Undefined behavior si riferisce a un codice di computer il cui comportamento è imprevedibile.

Almeno con gcc si otterrà un messaggio di avviso di conseguenza se gli avvertimenti sono attivati:

avvertimento: formato '% f' si aspetta digitare 'doppio', ma l'argomento 2 ha tipo 'int'

2

%f si aspetta double, ma si passa un valore int. È un comportamento indefinito.

La corretta sarebbe:

printf("line 5: %f\n",98.0); 
printf("line 6: %f\n",98.98); 
printf("line 5: %f\n",98.0); 
1

Se guardiamo il codice il compilatore produce vediamo la seguente:

00401B5E|>MOV DWORD PTR SS:[ESP+0x4],0x62       ; ||| 
00401B66|>MOV DWORD PTR SS:[ESP],arma_sto.00404024     ; |||ASCII "line 5: %f\n" 
00401B6D|>CALL <JMP.&msvcrt.printf>        ; ||\printf 
00401B72|>MOV DWORD PTR SS:[ESP+0x4],0x51EB851F     ; || 
00401B7A|>MOV DWORD PTR SS:[ESP+0x8],0x4058BEB8     ; || 
00401B82|>MOV DWORD PTR SS:[ESP],arma_sto.00404030     ; ||ASCII "line 6: %f\n" 
00401B89|>CALL <JMP.&msvcrt.printf>        ; |\printf 
00401B8E|>MOV DWORD PTR SS:[ESP+0x4],0x62       ; | 
00401B96|>MOV DWORD PTR SS:[ESP],arma_sto.00404024     ; |ASCII "line 5: %f\n" 
00401B9D|>CALL <JMP.&msvcrt.printf>        ; \printf 

Perché non hai gettato i due 98 valori float, l'output è casuale (basato sullo stack). Un input valido per% f è un numero di puntatore mobile, che prende due voci nello stack.

riga 4 non funziona perché è stata fornita solo una voce di stack.

linea 5 funziona bene, perché è un numero 98.98 puntatore mobile (che richiede due stack di voci)

linea 6 uscite ~ 98.98 perché il MOV 00401B7A non è annullata. Ciò significa che la riga 6 restituisce un valore float valido perché ha due voci di stack, ma il numero di puntatore mobile errato perché è presente una parte del numero precedente.

Soluzione, lanciato come float

printf("line 5: %f\n",(float)98); //output is 98.000000 
printf("line 6: %f\n",98.98); //output is 98.980000 
printf("line 5: %f\n",(float)98); //output is 98.000000 
Problemi correlati