Pergunta

Veja este snippet de código

int main()
{ 
 unsigned int a = 1000;
 int b = -1;
 if (a>b) printf("A is BIG! %d\n", a-b);
 else printf("a is SMALL! %d\n", a-b); 
 return 0;
}   

Isso fornece a saída: a é pequeno: 1001

Não entendo o que está acontecendo aqui. Como o> operador funciona aqui? Por que "A" menor que "B"? Se é realmente menor, por que recebo um número positivo (1001) como diferença?

Foi útil?

Solução

As operações binárias entre diferentes tipos integrais são realizadas dentro de um tipo "comum" definido pelo chamado Conversões aritméticas usuais (Veja a especificação do idioma, 6.3.1.8). No seu caso, o tipo "comum" é unsigned int. Isso significa que int operando (seu b) será convertido para unsigned int antes da comparação, bem como com o objetivo de realizar a subtração.

Quando -1 é convertido para unsigned int O resultado é o máximo possível unsigned int valor (o mesmo que UINT_MAX). Escusado será dizer que será maior do que o seu não assinado 1000 valor, significando que a > b é realmente falso e a é de fato pequena comparado com (unsigned) b. o if no seu código deve resolver else ramo, que é o que você observou em seu experimento.

As mesmas regras de conversão se aplicam à subtração. Sua a-b é realmente interpretado como a - (unsigned) b e o resultado tem tipo unsigned int. Esse valor não pode ser impresso com %d especificador de formato, já %d só funciona com assinado valores. Sua tentativa de imprimi -lo com %d resulta em comportamento indefinido, portanto, o valor que você vê impresso (mesmo que tenha uma explicação determinística lógica na prática) é completamente sem sentido do ponto de vista da linguagem C.

Editar: Na verdade, eu poderia estar errado sobre a parte indefinida de comportamento. De acordo com a especificação da linguagem C, a parte comum do intervalo do tipo inteiro assinado e não assinado correspondente deve ter representação idêntica (o que implica, de acordo com a nota de rodapé 31, "intercambiabilidade como argumentos nas funções"). Então, o resultado de a - b A expressão não é assinada 1001 Como descrito acima, e a menos que esteja perdendo alguma coisa, é legal imprimir esse valor não assinado específico com %d especificador, pois se enquadra na faixa positiva de int. Impressão (unsigned) INT_MAX + 1 com %d seria indefinido, mas 1001u está bem.

Outras dicas

Em uma implementação típica onde int é de 32 bits, -1 quando convertido em um unsigned int é 4.294.967.295, que é de fato ≥ 1000.

Mesmo se você tratar a subtração em um unsigned mundo, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 que é o que você recebe.

É por isso gcc vai cuspir um aviso quando você comparar unsigned com signed. (Se você não vir um aviso, passe o -Wsign-compare bandeira.)

Você está fazendo comparação não assinada, ou seja, comparando 1000 a 2^32 - 1.

A saída é assinada devido a %d no printf.

NB Às vezes, o comportamento quando você mistura operandos assinados e não assinados é específico do compilador. Eu acho que é melhor evitá -los e fazer elencos quando em dúvida.

Encontre uma maneira fácil de comparar, talvez útil quando você não pode se livrar da declaração não assinada (por exemplo, [contagem de nsarray]), basta forçar o "int não assinado" a um "int".

Por favor corrija-me se eu estiver errado.

if (((int)a)>b) {
    ....
}

O hardware foi projetado para comparar assinado com assinados e não assinados como não assinados.

Se você deseja o resultado aritmético, converta o valor não assinado em um tipo maior assinado primeiro. Caso contrário, o compilador assumirá que a comparação está realmente entre valores não assinados.

E -1 é representado como 1111..1111, por isso é uma quantidade muito grande ... a maior ... quando interpretada como não assinada.

 #include<stdio.h>
 int main()
 {
   int a = 1000;
   signed int b = -1, c = -2;
   printf("%d",(unsigned int)b);
   printf("%d\n",(unsigned int)c);
   printf("%d\n",(unsigned int)a);

   if(1000>-1){
      printf("\ntrue");
   }
   else 
     printf("\nfalse");
     return 0;
 }

Para isso, você precisa entender a precedência dos operadores

  1. Operadores relacionais trabalham da esquerda para a direita ... então quando chegar

    se (1000> -1)

Então, antes de tudo, ele mudará -1 para o número inteiro não assinado, porque o INT é por padrão tratado como número não assinado e ele é maior do que o número assinado

-1 mudará para o número não assinado, ele muda para um número muito grande

Ao comparar A> B, onde A não é assinado INT tipo e B é o tipo int, b é tipo escalado para não assinado int Portanto, o valor de int assinado -1 é convertido em valor máximo de não assinado ** (intervalo: 0 a (2^32) -1) ** Assim, a> b ie, (1000> 4294967296) se torna falso. Portanto, mais um loop printf ("A é pequeno! %d n", ab); executado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top