2011-09-20 66 views
14

我想通過閱讀C Programming Language, 2nd Edition來學習C語言。我有一些編程經驗,但不與C.在printf中使用%d時,浮點變量會發生什麼變化?

我在第1章目前是我有以下代碼:


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

它打印輸出:

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

看起來很好。


現在我改變的printf如下:

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

新的輸出

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

這是怎麼回事?我期望float會被轉換爲int,因爲我使用了%d,但那不是發生了什麼。另外,爲什麼值B也出錯?這裏發生了什麼事?

+2

你沒有要求它將它轉換爲int,你告訴它它**是** int!垃圾進垃圾出。 –

回答

15

時人稱:

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

Ç自動轉換floatdouble(它是在調用帶有可變參數的函數時進行的標準轉換,如int printf(const char *fmt, ...);)。爲了爭辯,我們將假設sizeof(int)是4,sizeof(double)是8(有例外,但它們很少和很遠)。

因此,該調用將一個指針壓入堆棧,外加一個8字節的雙精度型爲f,另一個爲的8字節雙精度型。在處理格式字符串時,%d告訴printf()您在格式字符串之後將4個字節的int壓入堆棧。由於這不是你所做的,你已經引用了未定義的行爲;根據C標準,接下來發生的任何事情都可以。

然而,最可能的實現會輕鬆地讀取4個字節並將它們打印出來,就好像它們是int(它相信您會說實話)。然後它遇到了%6.2f格式;它將以的形式從堆棧讀取8個字節。有一個外部機會,這會導致內存錯誤訪問不對齊(這需要一個64位機器,要求double與8字節邊界對齊,比如SPARC),否則會從中讀取4個字節f和4個字節從f + 0.15,把它們放在一起,創造一些相當意想不到的double值 - 如你的例子所示。

+0

很好的答案,所以你可以'printf(「A:%d%d B:%6.2」,...'並且弄錯了A vals但B不會受到影響 –

+1

在大量相當合理的假設下,行爲是嚴格不確定的,但實際上,是的。 –

8

printf會將您指向的內存視爲您告訴的內容。沒有轉換正在進行。它將表示float的內存視爲int。因爲兩者的儲存方式不同,所以您會得到本質上是隨機數的數據。

如果你想輸出你的流通量爲一個整數,你應該首先將它轉換:

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

好的,這是有道理的。那麼f的值是否會因爲我沒有將它轉換爲int而改變呢?如果不是,那麼printf的第二部分是使用%6.2f,那麼至少應該有正確的值? – Gollum

相關問題