C comportamento excesso de número inteiro ao atribuir a números inteiros maiores de largura
-
05-09-2019 - |
Pergunta
Se eu executar o seguinte código em C:
#include <stdint.h>
uint16_t a = 4000;
uint16_t b = 8000;
int32_t c = a - b;
printf("%d", c);
Ela imprime corretamente '-4000' como resultado. No entanto, estou um pouco confuso: não deve haver um estouro aritmético quando subtraindo um inteiro sem sinal maior do outro? Que regras de fundição estão em jogo aqui? Esta questão parece um noobish pouco, então qualquer referência seria muito apreciada.
Solução
A questão é realmente um pouco complicado. Operandos de expressões aritméticas são convertidos utilizando regras específicas que você pode ver na Seção 3.2.1.5 do padrão (C89) . No seu caso, a resposta depende do que o tipo uint16_t
é. Se for menor do que int
, short int
digamos, em seguida, os operandos são convertidos para int
e você começa -4000, mas em um sistema de 16 bits, uint16_t
poderia ser unsigned int
e conversão para um tipo assinado não aconteceria automaticamente.
Outras dicas
A resposta curta é que estes são todos promovidos a int
durante a subtração. Para a longa resposta, olhar na seção 6.3.1.1 do padrão C, onde ele fala sobre inteiros promoções em expressões aritméticas. idioma relevante do padrão:
Se um
int
pode representar todos os valores de o tipo de original, o valor é convertido para umint
; caso contrário, é convertido para umunsigned int
. Estes são chamados de promoções inteiros . Todos os outros tipos são inalterados pela promoções inteiros.
Os detalhes estão lá também, mas eles ficam bastante desagradável.
Ambos os operandos são promovidos a int32_t
durante a subtração. Se o resultado tinha sido maior do que o valor máximo para int32_t
você teria visto estouro.
Há, de fato, um estouro, mas C não lhe diz.
O estouro deixa um valor que passa a ser -4000 quando interpretado como um inteiro assinado. Isso funciona como projetado em máquinas complemento de 2.
Tente interpretar o resultado como não assinado, e você vai perceber que (u1-u2) avalia para um número aparentemente não relacionados quando u1