2013-03-29 47 views
16

此聲明編譯沒有以g ++ -pedantic -Wall(4.6.3版本)的警告:如何檢測分配給size_t的負數?

std::size_t foo = -42; 

不易察覺僞造被聲明一個具有爲size_t參數的函數,並具有負的值調用它。這樣的功能可以防止無意中的否定論證(其表現爲不符合第4.7條第2款的規定)?

不完整的答案:

只更改爲size_t至(簽字)長丟棄的語義和爲size_t等優點。

將其更改爲ssize_t只是POSIX,而不是標準。

將其更改爲ptrdiff_t是脆弱的,有時會損壞。

測試巨大的值(高位比特集等)是任意的。

+0

相關http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable – halex

+2

+1表示「不合格」。 Jk,+1,因爲這是一個很好的問題。 –

+0

謝謝你,halex。我剛剛從那裏引用了標準。 –

回答

3

對此發出警告的問題是,根據標準它不是未定義的行爲。如果將有符號值轉換爲相同大小的無符號類型,則可以稍後將其轉換回有符號值並在任何符合標準的編譯器上獲取原始值。

此外,使用轉換爲爲size_t負值是相當的各種錯誤情況常見的做法 - 許多系統調用用於錯誤返回-1(轉換爲無符號),用於成功還是無符號(size_toff_t)值。因此,向編譯器添加這樣的警告會導致大量現有代碼出現虛假警告。 POSIX試圖用ssize_t對此進行編碼,但是這會打破可能成功的呼叫,返回值大於ssize_t的最大簽名值。

+0

運行時檢測在這裏比編譯器警告更大的問題。但是你給了我這個想法,在函數內部,將值重新賦值爲<0的符號並進行測試。這樣可行。所以我會打電話給這個回答。 –

+0

@CamilleGoudeseune D'oh,轉換回簽名和測試<0是未定義的行爲。選擇一個最大值,例如'LONG_MAX'或'std :: numeric_limits :: max()',並將無符號值與該值進行比較,而不進行類型轉換。 – Potatoswatter

+0

@hvd:整體而言,規範確實允許使用相同大小的帶符號和無符號類型來回轉換,並獲得相同的值,即使範圍不同。 –

1

以下摘錄來自私人圖書館。

#include <limits.h> 

#if __STDC__ == 1 && __STDC_VERSION__ >= 199901L || \ 
    defined __GNUC__ || defined _MSC_VER 
    /* Has long long. */ 
    #ifdef __GNUC__ 
     #define CORE_1ULL __extension__ 1ULL 
    #else 
     #define CORE_1ULL 1ULL 
    #endif 
    #define CORE_IS_POS(x) ((x) && ((x) & CORE_1ULL << (sizeof (x)*CHAR_BIT - 1)) == 0) 
    #define CORE_IS_NEG(x) (((x) & CORE_1ULL << (sizeof (x)*CHAR_BIT - 1)) != 0) 
#else 
    #define CORE_IS_POS(x) ((x) && ((x) & 1UL << (sizeof (x)*CHAR_BIT - 1)) == 0) 
    #define CORE_IS_NEG(x) (((x) & 1UL << (sizeof (x)*CHAR_BIT - 1)) != 0) 
#endif 

#define CORE_IS_ZPOS(x) (!(x) || CORE_IS_POS(x)) 
#define CORE_IS_ZNEG(x) (!(x) || CORE_IS_NEG(x)) 

這應該適用於所有未簽名的類型。

+0

很好的使用CHAR_BIT,http://stackoverflow.com/a/3200969/2097284。但是什麼隱含的鑄造使這個工作? '(x)&...'將x投向ULL? '(x)&&'means'(x!= 0)&&'? ZPOS的意思是'> = 0'? –

+1

是的,'IS_POS' /'IS_NEG'測試'> 0'和'<0';和'IS_ZPOS' /'IS_ZNEG'測試'> = 0'和'<= 0'。沒有演員參與;宏只使用可用於構造位掩碼錶達式(因此UL和ULL)的最大無符號整數類型來測試最高位('(x)&...'部分)。 '(x)&& ...'部分就是簡單的'(x)!= 0'。 – alecov