2011-05-01 40 views
5

考慮下面的C程序:這是否會調用未定義的行爲?

#include <stdio.h> 

int main(){ 
    int a =-1; 
    unsigned b=-1; 
    if(a==b) 
     printf("%d %d",a,b); 
    else 
     printf("Unequal"); 
    return 0; 
} 

在線路printf("%d %d",a,b);"%d"用於打印的無符號類型。這是否會調用未定義的行爲,爲什麼?

回答

5

雖然明確允許使用va_arg宏從<stdarg.h>檢索被作爲unsignedint(7.15.1.1/2)傳遞一個參數,該文檔在fprintf(7.19.6.1/9)的也適用於printf,它明確規定,如果任何參數是不正確的類型格式說明 - 針對未修改%d,那就是int - 則行爲沒有定義。

正如評論@bdonlan筆記,如果b(對於一些N在這種情況下2^N - 1)的值不是在int表示的話那就未定義行爲嘗試使用訪問值作爲int無論如何都是va_arg。其中一個unsigned的表示中使用至少一個填充位,其中相應的int表示有符號位這隻會在平臺上工作。

即使在的(unsigned)-1值可以在int來表示的情況下,我仍然閱讀此爲技術上未定義的行爲。作爲執行工作的一部分,它似乎被允許採用工具使用內置的魔法,而不是va_args訪問參數printf,如果你傳遞的東西如其中需要int那麼你已經在技術上違反了合同的unsignedprintf

+0

7.15的異常.1.1/2的內容如下:「如果 類型與實際下一個參數[...]的類型不兼容,則行爲未定義,但[其中]一種類型是有符號整數類型,另一種類型是對應的無符號整數 類型,並且該值可以在兩個types_「(強調mine)中表示。由於'-1'在兩種類型中都不可表示,所以即使沒有7.19.6.1/9 – bdonlan 2011-05-01 21:42:16

+0

@bdonlan,行爲也是不確定的:從技術上講,'b'沒有值'-1',它的值是'2^N -1'代表一些'N'。這個值是否可以用int和unsigned來表示,取決於平臺 - 通常不是,我授予你。 – 2011-05-01 21:45:12

+0

如果只有某些實現定義的因子爲真時纔會定義某個行爲,則該行爲實際上是未定義的,因爲符合的實現可以自由選擇INT_MAX和UINT_MAX的值,以允許其在有問題的printf調用中召喚鼻子惡魔。 – bdonlan 2011-05-01 21:48:45

1

是的,if將始終評估爲true,printf將嘗試打印unsigned作爲signed。由於signed類型可能有陷阱表示,這可能是UB如果符號表示是一個補。

2

的標準是不是100%清楚這一點。一方面,你得到va_arg規範,它說(§7.15.1.1/ 2):

如果沒有實際的一個參數,或者如果 類型與實際的未來的類型兼容參數(如根據 到默認參數提升推動),其行爲是未定義的,除了以下 情況:

  • 一種類型是一個帶符號的整數類型,其他類型是相應的無符號整數 類型,價值可以在兩種類型中表示;
  • 一種類型是指向void,而另一個是一個指針,指向字符類型。

在另一方面,你得到的printf(§7.19.6規範。1/9):

如果任何參數是不正確的類型對應的轉換規範,其行爲是未定義「

因爲這幾乎是一個給定的printf將檢索論點。 va_arg,我會說你非常安全,可以在目標類型中表示值,但不能以其他方式表示。由於在傳遞之前已將-1轉換爲無符號,所以該值將超出範圍可以用帶符號的整數表示,所以行爲將是未定義的。

+0

除(無符號)-1成爲(UINT_MAX - 1),通常超出INT_MAX的範圍... – bdonlan 2011-05-01 21:50:05

+0

@bdonlan:糟糕 - 您是對的。編輯... – 2011-05-01 21:54:24

+0

我不知道是否有任何實現使用'%X'和帶有符號值的朋友除了顯示底層位的十六進制表示之外什麼都不做?如果不是這樣,這似乎是標準中應該提供的有用行爲,尤其是因爲很多現有代碼都依賴於該行爲。 – supercat 2015-12-16 18:36:29

相關問題