Advertencia del compilador (nivel 2) C4146
operador unario menos aplicado a un tipo sin signo; el resultado aún no tiene signo
Los tipos sin signo solo pueden contener valores no negativos, por lo que no suele tener sentido usar el operador unario menos (negación) cuando se aplica a un tipo sin signo. Tanto el operando como el resultado no son negativos.
Comentarios
Cuando se expresa un literal entero negativo, el -
delante del valor se analiza como un operador unario de negación. El compilador aplica el operador después de analizar el valor numérico. Si el valor numérico se ajusta al intervalo de un tipo entero sin signo, pero no al tipo entero con signo correspondiente, el compilador interpreta el valor como sin signo. El operador unario de negación no cambia un valor sin signo.
Esta advertencia suele producirse cuando se intenta expresar el valor int
mínimo, -2147483648, o el valor long long
mínimo, -9223372036854775808. Estos valores no se pueden escribir como -2147483648 o -9223372036854775808ll, respectivamente. El motivo es que el compilador procesa la expresión en dos fases: en primer lugar, analiza el valor numérico y, luego, aplica el operador de negación. Por ejemplo, cuando el compilador analiza -2147483648, sigue estos pasos:
Se evalúa el número 2147483648. Dado que es mayor que el valor
int
máximo de 2147483647, pero todavía cabe en ununsigned int
, el tipo de 2147483648 esunsigned int
.El operador unario menos se aplica al valor sin signo, con un resultado sin signo, el que también resulta ser 2147483648.
El tipo sin signo del resultado puede provocar un comportamiento inesperado. Si el resultado se usa en una comparación, se puede usar una comparación sin signo; por ejemplo, cuando el otro operando es int
.
Para evitar la advertencia C4146, use INT_MIN
o LLONG_MIN
desde <limits.h>
o el equivalente de C++, <climits>
. Estos valores tienen tipos con signo.
La opción del compilador /sdl
(Habilitar comprobaciones de seguridad adicionales) eleva esta advertencia a un error.
Ejemplo
En el ejemplo siguiente se muestra el comportamiento inesperado que puede producirse cuando el compilador genera la advertencia 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);
}
En este ejemplo, el compilador considera -9223372036854775808ll como sin signo, aunque el literal tenga un sufijo ll
y se aplique el operador de negación. Para hacer la comparación <
, el compilador promueve silenciosamente i
con signo a unsigned long long int
. La segunda línea esperada, 1 is greater than the most negative long long int
, no se imprime porque ((unsigned long long int)1) > 9223372036854775808ull
es false.
Para corregir el ejemplo, incluya <climits>
y cambie -9223372036854775808ll a LLONG_MIN
.