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:

  1. O número 2147483648 é avaliado. Como ele é maior que o valor máximo int de 2147483647, mas ainda cabe em um unsigned int, o tipo de 2147483648 é unsigned int.

  2. 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.

Confira também

Operador unário de negação (-)