分享方式:


編譯器警告 (層級 2) C4146

套用至不帶正負號類型的一元減號運算子,結果仍然未帶正負號

不帶正負號的類型只能保存非負值,因此一元減號(負號)在套用至不帶正負號的類型時通常沒有意義。 運算元和結果都是非負數。

備註

當您表示負整數常值時, - 值前面的 會剖析為 一元否定 運算子。 編譯器會在剖析數值之後套用 運算子。 如果數值符合不帶正負號的整數類型的範圍,但不符合對應的帶正負號整數類型,編譯器會將值解譯為不帶正負號。 一元負號運算子不會變更不帶正負號的值。

當您嘗試表示最小值 int -2147483648 或最小值 long long -9223372036854775808 時,通常會發生此警告。 這些值不能分別寫入為 -2147483648 或 -9223372036854775808ll。 原因是編譯器會以兩個階段處理運算式:首先,它會剖析數值,然後套用否定運算子。 例如,當編譯器剖析 -2147483648時,它會遵循下列步驟:

  1. 會評估2147483648數目。 因為它大於2147483647的最大值 int ,但仍符合 unsigned int ,所以 2147483648 的類型為 unsigned int

  2. 一元減號會套用至不帶正負號的值,並產生不帶正負號的結果,這也會發生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

另請參閱

一元負運算子 (-)