Qual é a diferença entre assinado e não assinado int?
Qual é a diferença entre assinado e não assinado int?
Respostas:
Como você provavelmente sabe, os int
s são armazenados internamente em binário. Normalmente, um int
conté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 int
ou 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 int
s o bit mais significativo é 1
se e somente se o número for negativo. É por isso que, para signed int
s, esse bit é conhecido como "bit de sinal".
(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.
int
e unsigned int
são dois tipos inteiros distintos. ( int
também pode ser referido como signed int
, ou apenas signed
; unsigned int
també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 int
pode representar apenas valores não negativos.
A linguagem C impõe alguns requisitos aos intervalos desses tipos. A faixa de int
tem de ser, pelo menos, -32767
.. +32767
, e o intervalo de unsigned int
tem 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. int
normalmente 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_MIN
e 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
.)
À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.
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.
Na prática, existem duas diferenças:
cout
em C ++ ou printf
em C): a representação do bit inteiro sem sinal é interpretada como um inteiro não negativo pelas funções de impressão.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");