Pergunta

Dado que assinados e ints usar o mesmo registra, etc., e apenas interpretar padrões de bits de forma diferente, e C caracteres são, basicamente, apenas 8-bit de ints, qual é a diferença entre assinados e caracteres em C?Eu entendo que o sinal de char é a aplicação definida, e eu simplesmente não consigo entender como ele poderia fazer a diferença, pelo menos quando o char é utilizado para armazenar seqüências de caracteres em vez de fazer matemática.

Foi útil?

Solução

Não fará diferença para as cordas. Mas em C você pode usar um char para fazer matemática, quando ele fará a diferença.

De fato, ao trabalhar em ambientes de memória restritos, como aplicativos incorporados de 8 bits, um char geralmente será usado para fazer matemática e, em seguida, faz uma grande diferença. Isso é porque não há byte Digite por padrão em C.

Outras dicas

Em termos dos valores que eles representam:

caracter não identifcado:

  • abrange a faixa de valor 0..255 (00000000..11111111)
  • Os valores transbordam em torno da borda baixa como:

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • Os valores transbordam em torno da borda alta como:

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • Operador de mudança direita bit -bit -in (>>) faz uma mudança lógica:

    10000000 >> 1 = 01000000 (128 / 2 = 64)

Char assinado:

  • abrange a faixa de valor -128..127 (10000000..01111111)
  • Os valores transbordam em torno da borda baixa como:

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • Os valores transbordam em torno da borda alta como:

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • Operador de mudança direita bit -bit -in (>>) faz uma mudança aritmética:

    10000000 >> 1 = 11000000 (-128 / 2 = -64)

Incluí as representações binárias para mostrar que o comportamento de embalagem de valor é aritmético binário puro e consistente e não tem nada a ver com um char sendo assinado/não assinado (espere para turnos certos).

Atualizar

Algum comportamento específico da implementação mencionado nos comentários:

#include <stdio.h>

int main(int argc, char** argv)
{
    char a = 'A';
    char b = 0xFF;
    signed char sa = 'A';
    signed char sb = 0xFF;
    unsigned char ua = 'A';
    unsigned char ub = 0xFF;
    printf("a > b: %s\n", a > b ? "true" : "false");
    printf("sa > sb: %s\n", sa > sb ? "true" : "false");
    printf("ua > ub: %s\n", ua > ub ? "true" : "false");
    return 0;
}


[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false

É importante ao classificar cordas.

Há algumas diferenças. Mais importante, se você transbordar o intervalo válido de um char atribuindo -lhe um número inteiro muito grande ou pequeno, e o char é assinado, o valor resultante é a implementação definida ou mesmo algum sinal (em c) pode ser aumentado, pois para todos os tipos assinados . Contraste isso com o caso em que você atribui algo muito grande ou pequeno a um char não assinado: o valor envolve, você terá uma semântica definida com precisão. Por exemplo, atribuindo um -1 a um char não assinado, você receberá um uchar_max. Portanto, sempre que você tem um byte como em um número de 0 a 2^char_bit, você realmente deve usar char não assinado para armazená -lo.

O sinal também faz a diferença ao passar para as funções vararg:

char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);

Suponha que o valor atribuído a C seria grande demais para o CHAR representar, e a máquina usa o complemento de dois. Muitas implementação se comportam para o caso de atribuir um valor muito grande ao char, pois o padrão de bits não mudará. Se um INT puder representar todos os valores de char (que é para a maioria das implementações), o char está sendo promovido a INT antes de passar para o PrintF. Portanto, o valor do que é passado seria negativo. Promover para o INT manteria esse sinal. Então você obterá um resultado negativo. No entanto, se o char não for assinado, o valor não será assinado e a promoção de um int produzirá um Int positivo. Você pode usar char não assinado e, em seguida, terá um comportamento definido com precisão para a atribuição para a variável e a passagem para o PrintF, que imprimirá algo positivo.

Observe que um char de char, não assinado e assinado, todos são pelo menos 8 bits de largura. Não há exigência de que o char seja exatamente 8 bits de largura. No entanto, para a maioria dos sistemas, isso é verdade, mas para alguns, você descobrirá que eles usam chars de 32 bits. Um byte em C e C ++ é definido para ter o tamanho de char; portanto, um byte em C também nem sempre é exatamente 8 bits.

Outra diferença é que, em C, um char não assinado não deve ter bits de preenchimento. Ou seja, se você encontrar char_bit é 8, os valores de um char não assinado devem variar de 0 .. 2^char_bit-1. O mesmo vale para o char se não for assinado. Para o char assinado, você não pode assumir nada sobre o intervalo de valores, mesmo que saiba como seu compilador implementa o material do sinal (o complemento de dois ou as outras opções), pode haver bits de preenchimento não utilizado. Em C ++, não há bits de preenchimento para todos os três tipos de caracteres.

"O que isso significa para um char ser assinado?"

Tradicionalmente, o conjunto de caracteres ASCII consiste em codificações de personagens de 7 bits. (Em oposição ao ebcidic de 8 bits.)

Quando o idioma C foi projetado e implementado, esse foi um problema significativo. (Por vários motivos, como a transmissão de dados em relação aos dispositivos de modem serial.) O bit extra tem usos como paridade.

Um "personagem assinado" é perfeito para essa representação.

Os dados binários, OTOH, estão simplesmente assumindo o valor de cada "pedaço" de dados de 8 bits, portanto, nenhum sinal é necessário.

Aritmética em bytes é importante para gráficos de computador (onde 8 bits valores são muitas vezes utilizados para armazenar cores).Além de que, eu posso pensar em dois casos principais, onde char sinal de questões:

  • a conversão para uma maior int
  • funções de comparação

A coisa desagradável é que estes não mordê-lo se todos os seus dados de seqüência de caracteres de 7 bits.No entanto, ele promete ser uma inesgotável fonte de obscurecer bugs se você está tentando fazer o seu programa C/C++ 8-bits limpo.

A assinatura funciona praticamente da mesma maneira chars como acontece em outros tipos integrais. Como você observou, os chars são realmente apenas um byte inteiros. (Não necessariamente de 8 bits, no entanto! Há uma diferença; um byte pode ser maior que 8 bits em algumas plataformas e chars estão bastante ligados a bytes devido às definições de char e sizeof(char). o CHAR_BIT macro, definido em <limits.h> ou C ++ 's <climits>, dirá quantos bits estão em um char.).

Quanto ao motivo pelo qual você deseja um personagem com um sinal: em C e C ++, não há tipo padrão chamado byte. Para o compilador, charS são bytes e vice -versa, e isso não distingue entre eles. Às vezes, porém, você quer - às vezes você querer este char Para ser um número de um byte e nesses casos (particularmente quão pequeno pode ter um byte), você também normalmente se importa se o número é assinado ou não. Eu pessoalmente usei a assinatura (ou não assinatura) para dizer que um certo char é um "byte" numérico) e não um personagem, e que será usado numericamente. Sem uma assinatura especificada, que char Realmente é um personagem e deve ser usado como texto.

Eu costumava fazer isso, sim. Agora as versões mais recentes de C e C ++ têm (u?)int_least8_t (atualmente digitado em <stdint.h> ou <cstdint>), que são mais explicitamente numéricos (embora normalmente sejam apenas digitados para assinados e não assinados char tipos de qualquer maneira).

A única situação em que posso imaginar que isso é um problema é se você optar por fazer matemática em chars. É perfeitamente legal escrever o seguinte código.

char a = (char)42;
char b = (char)120;
char c = a + b;

Dependendo da assinatura do char, C pode ser um dos dois valores. Se os chars não forem assinados, C será (char) 162. Se eles forem assinados, ele será um caso de transbordamento, pois o valor máximo para um char assinado é 128. Acho que a maioria das implementações retornaria (char) -32.

Uma coisa sobre chars assinados é que você pode testar C> = '' (espaço) e verifique se é um char ASCII imprimível normal. Claro, não é portátil, então não é muito útil.

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