簡體   English   中英

浮動混亂 - 我很困惑浮點說明符是如何發生的

[英]float confusion- I'm confused how float specifier occurs

請考慮以下代碼段

    float a=12.2;
    printf("%f %d",a,a); //output 12.200000 Garbage value

    printf("%d %f",a,a);//Output Garbage value Garbage Value

我的問題是為什么在第二個printf中,%d和%f都給出了垃圾值。 我知道這是因為我先用了%d?但是找不到任何正確的解釋..

對數據類型使用錯誤的轉換說明符會調用未定義的行為 您可能會得到任何預期或意外結果。

C11:7.21.6格式化輸入/輸出功能:

如果轉換規范無效,則行為未定義.282)如果任何參數不是相應轉換規范的正確類型,則行為未定義。

使用%d要打印的值afloat在程序的未定義的行為)的結果。

當您在printf使用錯誤的說明符時,可能會發生以下情況。

來電者這樣做:

  • 舉例來說,假設堆棧指針當前為100,並且參數以相反的順序被壓入堆棧。
  • 對於具有可變參數類型的函數, float參數將轉換為double
  • 對於printf("%d %f"), a, a) ,調用者首先將最后a放在堆棧上。 調用者通過將堆棧指針更改為92,將a轉換為double ,並將8個字節寫入堆棧,從而產生8個字節的空間。
  • 對於第一個a ,調用者將堆棧指針更改為84並將八個字節寫入堆棧。
  • 對於格式字符串"%d %f" ,調用者將堆棧指針更改為80並將四字節指針寫入堆棧。

然后printf這樣做:

  • printf初始化一個指向參數開始處的指針80。
  • 它在80處讀取指向字符串的指針。
  • 由於指針是四個字節,因此printf其參數指針更新為指向84。
  • 該字符串表示下一個參數是%d ,因此printf需要一個四字節整數,它從84讀取四個字節。
  • 由於int是四個字節,因此printf其參數指針更新為指向88。
  • 由於從84到91的八個字節包含double的編碼,因此從84到87的四個字節作為int沒有任何意義,而printf打印該位恰好表示的int值。
  • 該字符串表示下一個參數是%f ,因此printf需要一個8字節的double ,它從88開始讀取8個字節。
  • 從88到95的字節包含從第一個double的末尾開始的四個字節和從第二個double開始的四個字節,因此它們沒有任何意義作為doubleprintf打印出該位碰巧代表的任何值。

這不是所有C實現的工作方式,但是當您對printf使用不正確的參數時,可能會發生這種情況。 C標准使行為不確定,因為它不控制實現的工作方式,因此它們的行為可能如上所述,但是它們可能會在寄存器中傳遞某些參數。 在后一種情況下,您會看到不同的行為,例如%d printf打印垃圾,因為沒有將相應的整數寄存器設置為適當的值,但是printf打印了%f的正確值,因為它在浮點中查找它注冊,主叫方沒有地方的價值a在浮點寄存器。

因為你不知道會發生什么。 如果sizeof(float) != sizeof(int) ,你肯定會在第二種情況下得到兩次垃圾值,因為printf從第一個參數中讀取太多字節或太少的字節,所以當讀取下一個參數時它會搞砸參數(假設參數在堆棧上傳遞)。

出現的另一個問題是傳遞的參數被轉換為double ,它通常具有與int不同的大小,然后printf嘗試從double選擇一個int 尺寸不匹配(請參閱下面的評論)。

無論哪種方式,這都會調用未定義的行為,因此您實際上無法“期待”任何有意義的事情發生。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM