Compiler warning (level 2) C4146
unary minus operator applied to unsigned type, result still unsigned
Unsigned types can hold only non-negative values, so unary minus (negation) usually doesn't make sense when applied to an unsigned type. Both the operand and the result are non-negative.
Remarks
When you express a negative integer literal, the -
in front of the value is parsed as a unary negation operator. The compiler applies the operator after it parses the numeric value. If the numeric value fits in the range of an unsigned integer type, but not the corresponding signed integer type, the compiler interprets the value as unsigned. An unsigned value is unchanged by the unary negation operator.
This warning often occurs when you try to express the minimum int
value, -2147483648, or the minimum long long
value, -9223372036854775808. These values can't be written as -2147483648 or -9223372036854775808ll, respectively. The reason is because the compiler processes the expression in two stages: first, it parses the numeric value, then it applies the negation operator. For example, when the compiler parses -2147483648, it follows these steps:
The number 2147483648 is evaluated. Because it's greater than the maximum
int
value of 2147483647, but still fits in anunsigned int
, the type of 2147483648 isunsigned int
.Unary minus is applied to the unsigned value, with an unsigned result, which also happens to be 2147483648.
The unsigned type of the result can cause unexpected behavior. If the result is used in a comparison, then an unsigned comparison might be used, for example, when the other operand is an int
.
You can avoid C4146 by using INT_MIN
or LLONG_MIN
from <limits.h>
or the C++ equivalent, <climits>
. These values have signed types.
The /sdl
(Enable Additional Security Checks) compiler option elevates this warning to an error.
Example
The following sample demonstrates the unexpected behavior that can happen when the compiler generates warning 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);
}
In this example, the compiler considers -9223372036854775808ll unsigned even though the literal has an ll
suffix and the negation operator is applied. To make the <
comparison, the compiler silently promotes signed i
to unsigned long long int
. The expected second line, 1 is greater than the most negative long long int
, isn't printed because ((unsigned long long int)1) > 9223372036854775808ull
is false.
To fix the example, include <climits>
and change -9223372036854775808ll to LLONG_MIN
.