编译器警告(等级 2)C4146

一元负运算符应用于无符号类型,结果仍为无符号类型

无符号类型只能保留非负值,因此一元减号 (否定) 在应用于无符号类型时通常没有意义。 操作数和结果都是非负数。

备注

表示负整数文本时,值前面的 - 将解析为一元反数运算符。 编译器在分析数值后应用运算符。 如果数值适合无符号整数类型的范围,但不适合相应的有符号整数类型,编译器会将该值解释为无符号。 无符号值由一元求非运算符保持不变。

尝试表示最小值 int -2147483648 或最小值 long long -9223372036854775808 时,通常会发生此警告。 这些值不能分别写为 -2147483648 或 -9223372036854775808ll。 原因在于编译器在两个阶段中处理表达式:首先,它会分析数值,然后应用求非运算符。 例如,当编译器分析 -2147483648 时,它将遵循以下步骤:

  1. 计算数值 2147483648。 因为它大于最大值 int 2147483647,但仍适合 unsigned int,2147483648 的类型是 unsigned int

  2. 一元减号应用于无符号值,且结果为无符号,也就是 2147483648。

结果的无符号类型可能会导致意外行为。 如果在比较中使用了结果,则可以使用无符号比较,例如,当另一个操作数是 int 时。

可以使用 <limits.h>INT_MINLLONG_MIN,或者 C++ 等效项 <climits>,避免出现 C4146。 这些值具有有符号类型。

/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

另请参阅

一元求非运算符 (-)