Qual é a diferença entre assinado e não assinado int

91

Qual é a diferença entre assinado e não assinado int?

Moumita Das
fonte
5
Esta é uma pergunta real, e a resposta não é tão simples, mas sutil.
R .. GitHub PARAR DE AJUDAR O ICE
Votando para reabrir. Pode ser uma duplicata, mas é definitivamente uma questão real.
Brian de
4
Re: "Pode ser uma duplicata" - Qual é a diferença entre int não assinado e int assinado em C?
eldarerathis
Mais tags devem ser adicionadas, uma vez que muitos idiomas as usam.
Juan Boero
Esta questão pode precisar de um capítulo para ser elaborada. Se você quiser saber os prós e os contras, marque Inteiros não assinados e com sinal para obter mais explicações.
anônimo

Respostas:

113

Como você provavelmente sabe, os ints são armazenados internamente em binário. Normalmente, um intcontém 32 bits, mas em alguns ambientes pode conter 16 ou 64 bits (ou até mesmo um número diferente, geralmente, mas não necessariamente, uma potência de dois).

Mas para este exemplo, vamos olhar para inteiros de 4 bits. Minúsculo, mas útil para fins ilustrativos.

Como há quatro bits nesse número inteiro, ele pode assumir um de 16 valores; 16 é dois à quarta potência, ou 2 vezes 2 vezes 2 vezes 2. Quais são esses valores? A resposta depende se este inteiro é a signed intou an unsigned int. Com um unsigned int, o valor nunca é negativo; não há nenhum sinal associado ao valor. Aqui estão os 16 valores possíveis de um quatro bits unsigned int:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000    8
1001    9
1010   10
1011   11
1100   12
1101   13
1110   14
1111   15

... e aqui estão os 16 valores possíveis de um quatro bits signed int:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000   -8
1001   -7
1010   -6
1011   -5
1100   -4
1101   -3
1110   -2
1111   -1

Como você pode ver, para signed ints o bit mais significativo é 1se e somente se o número for negativo. É por isso que, para signed ints, esse bit é conhecido como "bit de sinal".

Bill Evans em Mariposa
fonte
11
Talvez valha a pena destacar que este é o formato de complemento de dois, que reconhecidamente é muito utilizado hoje em dia. Existem também outras maneiras de representar inteiros com sinal, mais notavelmente o complemento de um.
Schedler
Corrigir. E o padrão ISO9899 C nem mesmo exige que o complemento de um ou o complemento de dois seja usado; qualquer outra convenção que realmente funcione é permitida.
Bill Evans em Mariposa,
1
Embora o complemento de dois não seja necessário, (unsigned)(-1)é necessário que seja o valor máximo representável para unsigned(independente da representação binária), o que é trivialmente verdadeiro para o complemento de 2, mas não para outras representações.
rubenvb
3
@BillEvansatMariposa: O padrão diz que para inteiros com sinal existem 3 representações permitidas: sinal + magnitude, complemento de 2, complemento de 1. Qualquer outro teria que ser invisível para o programa e ser percebido como um destes 3.
Alexey Frunze
Ok, mas sob o capô! O que REALMENTE está acontecendo! Qual é a diferença entre um número ASSINADO e NÃO ASSINADO! Como a máquina gerencia a computação? Ele apenas subtrai um valor do outro? Como ele difere 1111 = 15 e 1111 = -1?
Mihail Georgescu
19

inte unsigned intsão dois tipos inteiros distintos. ( inttambém pode ser referido como signed int, ou apenas signed; unsigned inttambém pode ser referido como unsigned.)

Como o nome implica, inté um assinado tipo inteiro, e unsigned inté um sem assinatura tipo inteiro. Isso significa que inté capaz de representar valores negativos e unsigned intpode representar apenas valores não negativos.

A linguagem C impõe alguns requisitos aos intervalos desses tipos. A faixa de inttem de ser, pelo menos, -32767.. +32767, e o intervalo de unsigned inttem de ser, pelo menos, 0.. 65535. Isso significa que ambos os tipos devem ter pelo menos 16 bits. Eles têm 32 bits em muitos sistemas, ou mesmo 64 bits em alguns. intnormalmente tem um valor negativo extra devido à representação de complemento de dois usada pela maioria dos sistemas modernos.

Talvez a diferença mais importante seja o comportamento da aritmética com sinal vs. sem sinal. Para assinados int, o estouro tem comportamento indefinido. Pois unsigned int, não há transbordamento; qualquer operação que produza um valor fora do intervalo do tipo envolve, por exemplo UINT_MAX + 1U == 0U.

Qualquer tipo de inteiro, com ou sem sinal, modela uma subfaixa do conjunto infinito de inteiros matemáticos. Desde que você trabalhe com valores dentro da faixa de um tipo, tudo funciona. Ao se aproximar do limite inferior ou superior de um tipo, você encontra uma descontinuidade e pode obter resultados inesperados. Para tipos inteiros com sinal, os problemas ocorrem apenas para valores negativos e positivos muito grandes, excedendo INT_MINe INT_MAX. Para tipos inteiros sem sinal, ocorrem problemas para valores positivos muito grandes e em zero . Isso pode ser uma fonte de bugs. Por exemplo, este é um loop infinito:

for (unsigned int i = 10; i >= 0; i --) [
    printf("%u\n", i);
}

porque ié sempre maior ou igual a zero; essa é a natureza dos tipos sem sinal. (Dentro do loop, quando ié zero, i--define seu valor como UINT_MAX.)

Keith Thompson
fonte
12

Às vezes sabemos de antemão que o valor armazenado em uma determinada variável inteira será sempre positivo - quando está sendo usado apenas para contar coisas, por exemplo. Nesse caso, podemos declarar a variável sem sinal, como em unsigned int num student;,. Com tal declaração, o intervalo de valores inteiros permitidos (para um compilador de 32 bits) mudará do intervalo -2147483648 a +2147483647 para o intervalo 0 a 4294967295. Assim, declarar um número inteiro como não assinado quase duplica o tamanho do maior possível valor que ele pode conter.

imran
fonte
@Alex Eu estava editando essa resposta há 10 minutos e ela é idêntica. lol
Skuld
12

Em termos leigos, um int sem sinal é um número inteiro que não pode ser negativo e, portanto, tem um intervalo maior de valores positivos que pode assumir. Um int com sinal é um inteiro que pode ser negativo, mas tem um intervalo positivo inferior em troca de valores mais negativos que pode assumir.

user2977636
fonte
0

Na prática, existem duas diferenças:

  1. impressão (por exemplo, com coutem C ++ ou printfem C): a representação do bit inteiro sem sinal é interpretada como um inteiro não negativo pelas funções de impressão.
  2. pedido : o pedido depende da especificação assinada ou não assinada.

este código pode identificar o inteiro usando o critério de pedido:

char a = 0;
a--;
if (0 < a)
    printf("unsigned");
else
    printf("signed");
Minimus Heximus
fonte
Se isso explicasse a diferença, um lidando com números negativos e o outro, não. Isso ajudaria muito neste post.
Daniel Jackson
@DanielJackson Não está claro o que você diz. um char pode ser considerado negativo ou positivo dependendo do compilador. a saída do código depende do que o compilador escolhe e isso mostra a diferença entre assinado e não assinado.
Minimus Heximus