簡體   English   中英

為什么這個代碼打印0?

[英]Why is this code printing 0?

void main()
{
    clrscr();
    float f = 3.3;

    /* In printf() I intentionaly put %d format specifier to see
       what type of output I may get */
    printf("value of variable a is: %d", f);
    getch();
}

實際上, %d告訴printf在某個位置查找整數參數。 但是你傳遞了一個float參數,它被放在不同的地方。 C 標准沒有指定執行此操作時會發生什么。 在這種情況下,可能在printf尋找整數參數的地方有一個零,所以它打印了“0”。 在其他情況下,可能會發生不同的事情。

printf使用無效的格式說明符會調用未定義的行為 這在C 標准的第 7.21.6.1p9 節中指定:

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

這意味着您無法可靠地預測程序的輸出結果。 例如,我系統上的相同代碼打印 -1554224520 作為值。

至於最有可能發生的情況, %d格式說明符正在尋找一個int作為參數。 假設一個int被堆棧和一個通過int是4個字節長,則printf功能着眼於堆棧中給出的值上的下一個4個字節。 許多實現不會在堆棧上傳遞浮點值,而是在寄存器中傳遞,因此它會看到碰巧在那里的任何垃圾值。 即使在堆棧上傳遞floatfloatint具有非常不同的表示形式,因此將float的字節打印為int很可能不會為您提供相同的值。

讓我們看一個不同的例子。 假設我寫

#include <string.h>

char buf[10];
float f = 3.3;
memset(buf, 'x', f);

memset的第三個參數應該是一個整數(實際上是一個size_t類型的值),告訴memset要將多少個buf字符設置為'x' 但是我傳遞了一個float值。 發生什么了? 好吧,編譯器知道第三個參數應該是一個整數,所以它會自動執行適當的轉換,代碼最終將buf的前三個(三個點)字符設置為'x'

(重要的是,編譯器知道memset的第三個參數應該是整數的方式是基於memset原型函數聲明,它是頭文件<string.h> 。)

現在,當你打電話

printf("value of variable f is: %d", f);

你可能認為同樣的事情會發生。 您傳遞了一個float ,但%d需要一個int ,因此會發生自動轉換,對嗎?

錯誤的。 讓我再說一遍:錯了

也許令人驚訝的事實是, printf是不同的。 printf很特別。 編譯器不一定知道傳遞給printf的參數的正確類型應該是什么,因為這取決於隱藏在格式字符串中的%說明符的詳細信息。 所以沒有自動轉換到正確的類型。 您的工作是確保您實際傳遞的參數類型完全適合格式說明符。 如果它們不匹配,編譯器不會自動執行相應的轉換。 如果它們不匹配,就會發生瘋狂的錯誤結果。

printf的原型函數聲明是什么樣的?字面上看起來像這樣: extern int printf(const char *, ...); 。這三個點...表示可變長度參數列表或“varargs”,它們告訴編譯器它不知道還有多少參數,或者它們的類型應該是什么。所以編譯器執行一些基本的轉換——比如將類型charshort int上轉換為int ,並將floatdouble ——然后就這樣了。)

我說“編譯器不一定知道傳遞給printf的參數的正確類型應該是什么”,但是現在,好的編譯器會加倍努力並嘗試弄清楚,如果可以的話。 他們仍然不會執行自動轉換(根據語言規則,他們實際上不被允許這樣做),但他們至少可以警告您。 例如,我在兩個不同的編譯器下嘗試了您的代碼。 兩者都說了一些warning: format specifies type 'int' but the argument has type 'float' 如果您的編譯器沒有給您這樣的警告,我鼓勵您查明是否可以啟用這些警告,或者考慮切換到更好的編譯器。

嘗試

printf("... %f",f); 

這就是您打印浮點數的方式 也許您只想打印f 的x 位數字,例如:

printf("... %.3f" f);

這將在點后打印 3 位數字的浮點數。 請通讀此列表:

%c - 字符

%d 或 %i - 有符號十進制整數

%e - 使用 e 字符的科學記數法(尾數/指數)

%E - 使用 E 字符的科學記數法(尾數/指數)

%f - 十進制浮點數

%g - 使用 %e 或 %f 中的較短者

%G - 使用 %E 或 %f 中的較短者

%o - 有符號八進制

%s - 字符串

%u - 無符號十進制整數

%x - 無符號十六進制整數

%X - 無符號十六進制整數(大寫字母)

%p - 指針地址

%n - 未打印任何內容

代碼打印 0,因為您使用的是格式標記 %d,它表示有符號十進制整數 ( http://devdocs.io )。

你能試試嗎

void main() {

   clrscr();
   float f=3.3;

   /* In printf() I intentionaly put %d format specifier to see what type of output I may get */

   printf("value of variable a is: %f",f); 
   getch();

}

暫無
暫無

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

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