Aritmética C++ com tipos integrais mistos que causam estouro
-
21-12-2019 - |
Pergunta
Fiz alguns testes no VC++2010 misturando operandos de diferentes tamanhos que causam overflow na operação add:
int _tmain(int argc, _TCHAR* argv[])
{
__int8 a=127;
__int8 b=1;
__int16 c=b+a;
__int8 d=b+a;
printf("c=%d,d=%d\n",c,d);
return 0;
}
//result is: c=128, d=-128
Não entendo porque c==128!Meu entendimento é que em ambas as adições, b+a ainda são considerados adição de 2 assinados 8 bits variáveis.Portanto, o resultado é um estouro, ou seja,-128. Depois disso, o resultado é então promovido para int assinado de 16 bits para a primeira operação de atribuição e c ainda deve obter um valor -128 de 16 bits.Meu entendimento está correto?O padrão c++ é um pouco difícil de ler.O capítulo 4 parece falar sobre promoção inteira, mas não consigo encontrar nada relacionado a este exemplo específico.
Solução
Meu entendimento é que em ambas as adições, b+a ainda são consideradas adição de 2 variáveis assinadas de 8 bits.Portanto, o resultado é um estouro, ou seja,-128.
Não, a promoção acontece antes do +
é avaliado, não depois dele.A adição acontece quando ambos a
e b
são positivos.Ambos os números são promovidos para int
s para uma adição, adicionados como dois números positivos e depois convertidos em um número curto de 16 bits.Em nenhum momento do processo o resultado se torna negativo devido a um estouro, daí o resultado final de 128.
Indiscutivelmente, isso faz sentido:o comportamento de a
e b
corresponde ao de dois números em matemática, tornando-o mais intuitivo para os profissionais de línguas.
Outras dicas
É promoção integral.
1 Um pré-valor de um tipo inteiro diferente de bool, char16_t, char32_t ou wchar_t cuja classificação de conversão de inteiro (4.13) é menor que a classificação de int pode ser convertido em um pré-valor do tipo int se int puder representar todos os valores do tipo de origem ;caso contrário, o pré-valor de origem poderá ser convertido em um pré-valor do tipo unsigned int.[§ 4.5]
Nesta declaração
__int16 c=b+a;
Primeiro, tudo
char
eshort int
valores são automaticamente elevados paraint
.Este processo é chamado promoção integral.A seguir, todos os operandos são convertidos até o tipo do maior operando, que é denominado digite promoção.[Herbert Schildt]
O valores de variáveis b
e a
será promovido a int
e então a operação se aplica a eles.
Na representação inteira com complemento de dois, um valor com sinal é representado definindo o bit mais alto.Isso permite que a máquina adicione e subtraia números inteiros binários com as mesmas instruções, independentemente de o número inteiro estar assinado.
a = 127 == 0x7F == 0b01111111
+ b = 1 == 0x01 == 0b00000001
-------------------------------
c = 128 == 0x80 == 0b10000000
d =-128 == 0x80 == 0b10000000
As variáveis c
e d
podem ter tipos diferentes, mas diferentes tipos de números inteiros são apenas interpretações diferentes de um único valor binário.Como você pode ver acima, o valor binário cabe perfeitamente em 8 bits.Como o padrão exige que os termos de uma expressão matemática sejam estendidos (promovidos) com zero ou sinal até o tamanho de uma palavra de máquina antes qualquer matemática é feita e nenhum operando será estendido por sinal, o resultado é sempre 0b10000000
não importa o tipo dos operandos.
Em resumo, a diferença entre os resultados é que, para um número inteiro de 16 bits, o bit de sinal é 0b1000000000000000
(qual a+b
não tem), e para um número inteiro de 8 bits o bit de sinal é 0b10000000
(qual a+b
tem).