編譯器警告 (層級 2) C4146
套用至不帶正負號類型的一元減號運算子,結果仍然未帶正負號
不帶正負號的類型只能保存非負值,因此一元減號(負號)在套用至不帶正負號的類型時通常沒有意義。 運算元和結果都是非負數。
備註
當您表示負整數常值時, -
值前面的 會剖析為 一元否定 運算子。 編譯器會在剖析數值之後套用 運算子。 如果數值符合不帶正負號的整數類型的範圍,但不符合對應的帶正負號整數類型,編譯器會將值解譯為不帶正負號。 一元負號運算子不會變更不帶正負號的值。
當您嘗試表示最小值 int
-2147483648 或最小值 long long
-9223372036854775808 時,通常會發生此警告。 這些值不能分別寫入為 -2147483648 或 -9223372036854775808ll。 原因是編譯器會以兩個階段處理運算式:首先,它會剖析數值,然後套用否定運算子。 例如,當編譯器剖析 -2147483648時,它會遵循下列步驟:
會評估2147483648數目。 因為它大於2147483647的最大值
int
,但仍符合unsigned int
,所以 2147483648 的類型為unsigned int
。一元減號會套用至不帶正負號的值,並產生不帶正負號的結果,這也會發生2147483648。
結果的不帶正負號類型可能會導致非預期的行為。 如果在比較中使用結果,則當另一個運算元是 int
時,可能會使用不帶正負號的比較。
您可以使用 或 來自 <limits.h>
或 LLONG_MIN
C++ 對等的 C4146 來避免 C4146 INT_MIN
。 <climits>
這些值具有帶正負號的類型。
[啟用其他安全性檢查] 編譯器選項會將 /sdl
這個警告提升為錯誤。
範例
下列範例示範編譯器產生警告 C4146 時可能發生的非預期行為:
// C4146.cpp
// compile with: /W2
#include <iostream>
void check(int i)
{
if (i > -9223372036854775808ll) // C4146
std::cout << i << " is greater than the most negative long long int.\n";
}
int main()
{
check(-100);
check(1);
}
在此範例中,編譯器會考慮 -9223372036854775808ll 不帶正負號,即使常值具有 ll
尾碼,而且套用否定運算子。 為了進行 <
比較,編譯器會以無訊息方式將已簽署 i
的 升級為 unsigned long long int
。 預期的第二行 1 is greater than the most negative long long int
不會列印,因為 ((unsigned long long int)1) > 9223372036854775808ull
為 false。
若要修正此範例,請將 <climits>
-9223372036854775808ll 變更為 LLONG_MIN
。