Aviso do compilador (nível 2) C4146
um operador de subtração unária foi aplicado a tipo sem sinal, resultado permanece sem sinal
Tipos não assinados podem conter apenas valores não negativos, portanto, a subtração unária (negação) geralmente não faz sentido quando aplicado a um tipo não assinado. O operando e o resultado não são negativos.
Comentários
Quando você expressa um literal inteiro negativo, o -
na frente do valor é analisado como um operador de negação unária. O compilador aplica o operador depois de analisar o valor numérico. Se o valor numérico couber no intervalo de um tipo inteiro sem sinal, mas não o tipo inteiro com sinal correspondente, o compilador interpretará o valor como não assinado. Um valor não assinado é inalterado pelo operador de negação unária.
Esse aviso geralmente ocorre quando você tenta expressar o valor mínimo int
, -2147483648 ou o valor mínimo long long
, -9223372036854775808. Esses valores não podem ser gravados como -2147483648 ou -9223372036854775808ll, respectivamente. Isso ocorre porque o compilador processa a expressão em duas fases: primeiro, ele analisa o valor numérico e aplica o operador de negação. Por exemplo, quando o compilador analisa -2147483648, ele segue estas etapas:
O número 2147483648 é avaliado. Como ele é maior que o valor máximo
int
de 2147483647, mas ainda cabe em umunsigned int
, o tipo de 2147483648 éunsigned int
.A subtração unária é aplicada ao valor não assinado, com um resultado não assinado, que também é 2147483648.
O tipo não assinado do resultado pode causar um comportamento inesperado. Se o resultado for usado em uma comparação, uma comparação não assinada poderá ser usada, por exemplo, quando o outro operando for um int
.
Você pode evitar c4146 usando INT_MIN
ou LLONG_MIN
a partir de <limits.h>
ou o equivalente em C++, <climits>
. Esses valores têm tipos assinados.
A opção do compilador /sdl
(Habilitar Verificações de Segurança Adicionais) eleva esse aviso a um erro.
Exemplo
O exemplo a seguir demonstra o comportamento inesperado que pode acontecer quando o compilador gera um aviso 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);
}
Neste exemplo, o compilador considera -9223372036854775808ll sem sinal, embora o literal tenha um sufixo ll
e o operador de negação seja aplicado. Para fazer a comparação <
, o compilador promove silenciosamente o i
assinado a unsigned long long int
. A segunda linha esperada, 1 is greater than the most negative long long int
, não é impressa porque ((unsigned long long int)1) > 9223372036854775808ull
é falso.
Para corrigir o exemplo, inclua <climits>
e altere -9223372036854775808ll para LLONG_MIN
.