Em C / C ++, para que unsigned char
é usado? Como é diferente de um regular char
?
Em C / C ++, para que unsigned char
é usado? Como é diferente de um regular char
?
Respostas:
No C ++, existem três tipos de caracteres distintos :
char
signed char
unsigned char
Se você estiver usando tipos de caracteres para texto , use o não qualificado char
:
'a'
ou '0'
."abcde"
Também funciona como um valor numérico, mas não é especificado se esse valor é tratado como assinado ou não. Cuidado com as comparações de caracteres por meio de desigualdades - embora se você se limitar a ASCII (0-127), estará quase seguro.
Se você estiver usando tipos de caracteres como números , use:
signed char
, que fornece pelo menos o intervalo de -127 a 127. (-128 a 127 é comum)unsigned char
, que fornece pelo menos o intervalo de 0 a 255."Pelo menos", porque o padrão C ++ fornece apenas o intervalo mínimo de valores que cada tipo numérico é necessário para cobrir. sizeof (char)
é necessário que seja 1 (ou seja, um byte), mas em teoria um byte pode ter, por exemplo, 32 bits. sizeof
ainda seria informar seu tamanho como1
- o que você poderia ter sizeof (char) == sizeof (long) == 1
.
sizeof
porque não é uma função, mas um operador. É imho um estilo ainda melhor para omitir os parênteses quando se assume o tamanho de uma variável. sizeof *p
ou sizeof (int)
. Isso deixa claro rapidamente se se aplica a um tipo ou variável. Da mesma forma, também é redundante colocar parênteses depois return
. Não é uma função.
char
: é o tipo de literal de caractere como 'a'
ou '0'
." é verdadeiro em C ++, mas não em C. Em C, 'a'
é um int
.
Isso depende da implementação, pois o padrão C NÃO define a assinatura de char
. Dependendo da plataforma, char pode ser signed
ou unsigned
, portanto, você precisa solicitar explicitamente signed char
ou unsigned char
se sua implementação depende disso. Basta usar char
se você pretende representar caracteres de cadeias, pois isso corresponderá ao que sua plataforma coloca na cadeia.
A diferença entre signed char
e unsigned char
é como você esperaria. Na maioria das plataformas, signed char
haverá um número de complemento de dois bits de 8 bits que varia de -128
a 127
e unsigned char
será um número inteiro não assinado de 8 bits ( 0
para 255
). Observe que o padrão NÃO exige que os char
tipos tenham 8 bits, apenas esse sizeof(char)
retorno 1
. Você pode obter o número de bits em um caractere com CHAR_BIT
in limits.h
. Hoje existem poucas plataformas, se houver alguma, em que isso será algo diferente 8
.
Há um bom resumo dessa questão aqui .
Como outros já mencionaram desde que eu postei isso, é melhor você usar int8_t
e uint8_t
se realmente deseja representar números inteiros pequenos.
CHAR_BIT
é necessário ter pelo menos 8 bits pelo padrão.
Porque eu sinto que é realmente necessário, eu só quero declarar algumas regras de C e C ++ (elas são as mesmas a esse respeito). Primeiro, todos os bits de unsigned char
participar na determinação do valor se qualquer objeto sem assinatura char. Segundo, unsigned char
é explicitamente declarado sem sinal.
Agora, tive uma discussão com alguém sobre o que acontece quando você converte o valor -1
do tipo int unsigned char
. Ele recusou a ideia de que o resultado unsigned char
tenha todos os bits definidos como 1, porque estava preocupado com a representação de sinais. Mas ele não precisa. Imediatamente após esta regra, a conversão faz o que se destina:
Se o novo tipo não estiver assinado, o valor será convertido adicionando ou subtraindo repetidamente um mais que o valor máximo que pode ser representado no novo tipo até que o valor esteja no intervalo do novo tipo. (
6.3.1.3p2
em um rascunho de C99)
Essa é uma descrição matemática. O C ++ o descreve em termos de módulo de cálculo, que gera a mesma regra. De qualquer forma, o que não é garantido é que todos os bits no número inteiro -1
são um antes da conversão. Então, o que temos para afirmar que o resultado unsigned char
tem todos os seus CHAR_BIT
bits voltados para 1?
UCHAR_MAX+1
para -1
produzirá um valor no intervalo, ou seja,UCHAR_MAX
Já chega, na verdade! Então, sempre que você quiser unsigned char
ter todos os seus bits um, faça
unsigned char c = (unsigned char)-1;
Segue-se também que uma conversão não está apenas truncando bits de ordem superior. O evento feliz para o complemento de dois é que é apenas um truncamento, mas o mesmo não é necessariamente verdadeiro para outras representações de signos.
UCHAR_MAX
?
(unsigned type)-1
é algum tipo de linguagem. ~0
não é.
int x = 1234
e char *y = &x
. Representação binária de 1234
é 00000000 00000000 00000100 11010010
. Minha máquina é pouco endian e, portanto, a reverte e armazena na memória que o 11010010 00000100 00000000 00000000
LSB vem em primeiro lugar. Agora parte principal. se eu usar printf("%d" , *p)
. printf
lerá primeiro byte 11010010
apenas a saída é, -46
mas 11010010
é 210
por isso que ela é impressa -46
. Estou realmente confuso, eu acho que algum char para promoção inteira está fazendo algo, mas eu não sei.
Como, por exemplo, usos de caracteres não assinados :
unsigned char
é frequentemente usado em computação gráfica, que muitas vezes (embora nem sempre) atribui um único byte a cada componente de cor. É comum ver uma cor RGB (ou RGBA) representada como 24 (ou 32) bits, cada um unsigned char
. Como os unsigned char
valores caem no intervalo [0,255], os valores são geralmente interpretados como:
Assim, você terminaria com o vermelho RGB como (255,0,0) -> (100% vermelho, 0% verde, 0% azul).
Por que não usar um signed char
? A aritmética e a troca de bits se tornam problemáticas. Como já explicado, signed char
o intervalo de a é essencialmente deslocado por -128. Um método muito simples e ingênuo (principalmente não utilizado) para converter RGB em escala de cinza é calcular a média dos três componentes de cores, mas isso ocorre quando os valores dos componentes de cores são negativos. A média de vermelho (255, 0, 0) é de (85, 85, 85) ao usar unsigned char
aritmética. No entanto, se os valores fossem signed char
s (127, -128, -128), terminaríamos com (-99, -99, -99), que seria (29, 29, 29) em nosso unsigned char
espaço, o que está incorreto .
Se você deseja usar um caractere como um número inteiro pequeno, a maneira mais segura de fazer isso é com os tipos int8_t
euint8_t
int8_t
e uint8_t
são opcionais e não definida em arquiteturas onde o tamanho byte não é exatamente 8 bits. Por outro lado, signed char
e unsigned char
estão sempre disponíveis e garantidos para conter pelo menos 8 bits. Pode ser uma maneira comum , mas não a mais segura .
signed char
e unsigned char
? Ou você recomendaria uma alternativa melhor "mais segura" nesse caso específico? Por exemplo, ficar com os tipos inteiros "reais" signed int
e, unsigned int
por algum motivo?
signed char
e unsigned char
é portátil para todas as implementações em conformidade e economizará espaço de armazenamento, mas poderá causar algum aumento no tamanho do código. Em alguns casos, economizaria mais espaço de armazenamento armazenando pequenos valores em campos de bits ou bits únicos de tipos inteiros regulares. Não há resposta absoluta para essa pergunta, a pertinência dessa abordagem depende do caso específico em questão. E esta resposta não aborda a questão de qualquer maneira.
char
e unsigned char
não são garantidos tipos de 8 bits em todas as plataformas - eles têm 8 bits ou mais. Algumas plataformas têm bytes de 9, 32 ou 64 bits . No entanto, as plataformas mais comuns hoje em dia (Windows, Mac, Linux x86 etc.) possuem bytes de 8 bits.
signed char
tem um intervalo de -128 a 127; unsigned char
tem intervalo de 0 a 255.
char
será equivalente a um caractere assinado ou não assinado, dependendo do compilador, mas é um tipo distinto.
Se você estiver usando seqüências de caracteres em estilo C, use char
. Se você precisar usar chars para aritmética (bastante raro), especifique assinado ou não assinado explicitamente para portabilidade.
An unsigned char
é um valor de byte não assinado (0 a 255). Você pode estar pensando char
em termos de ser um "personagem", mas é realmente um valor numérico. O regular char
é assinado, então você tem 128 valores e esses valores são mapeados para caracteres usando a codificação ASCII. Mas em ambos os casos, o que você está armazenando na memória é um valor de byte.
Em termos de valores diretos, um caractere comum é usado quando se sabe que os valores estão entre CHAR_MIN
e CHAR_MAX
enquanto um caractere não assinado fornece o dobro do intervalo na extremidade positiva. Por exemplo, se CHAR_BIT
for 8, o intervalo de regular char
é garantido apenas como [0, 127] (porque pode ser assinado ou não assinado) enquanto unsigned char
será [0, 255] e signed char
será [-127, 127].
Em termos de para que é usado, os padrões permitem que objetos de POD (dados antigos simples) sejam diretamente convertidos em uma matriz de caracteres não assinados. Isso permite que você examine a representação e os padrões de bits do objeto. A mesma garantia de punção de tipo seguro não existe para char ou char assinado.
unsigned char
, e não uma matriz especificamente, & qualquer "conversão" só é formalmente definido por cópia do objecto para uma verdadeira, declarado gama de unsigned char
&, em seguida, inspeccionar o último. Não está claro se o OR pode ser reinterpretado diretamente como uma matriz, com as permissões para a aritmética do ponteiro que isso implicaria, ou seja, se "seqüência" ==
"matriz" nesse uso. Há um problema central nº 1701 aberto na esperança de esclarecer isso. Felizmente, como essa ambiguidade está realmente me incomodando recentemente.
unsigned char
da ++ptr
sala de cirurgia e continuar usando a partir daí para ler todos os bytes ... mas AFAICT, não é definido especificamente como permitido, então estamos resta inferir que é 'provavelmente OK' de muitas outras passagens (e de muitas maneiras, a mera existência de memcpy
) no Padrão, semelhante a um quebra-cabeça. O que não é o ideal. Bem, talvez a redação melhore eventualmente. Aqui está o problema do CWG que mencionei, mas sem espaço para vincular - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
unsigned char
é o coração de todos os truques. Em quase TODO o compilador para TODA a plataforma, um unsigned char
é simplesmente um byte e um número inteiro não assinado de (geralmente) 8 bits que podem ser tratados como um número inteiro pequeno ou um pacote de bits.
Além disso, como alguém já disse, o padrão não define o sinal de um caractere. então você tem 3 diferentes char
tipos: char
, signed char
, unsigned char
.
Se você gosta de usar vários tipos de comprimento e de assinatura específica, você é provavelmente melhor fora com uint8_t
, int8_t
, uint16_t
, etc, simplesmente porque eles fazem exatamente o que eles dizem.
Alguns pesquisadores descobriram isso , onde as pessoas discutiram sobre isso.
Um caracter não assinado é basicamente um byte único. Portanto, você usaria isso se precisar de um byte de dados (por exemplo, talvez você queira usá-lo para ativar e desativar sinalizadores para serem passados para uma função, como costuma ser feito na API do Windows).
Um caractere não assinado usa o bit reservado para o sinal de um caractere regular como outro número. Isso altera o intervalo para [0 - 255] em oposição a [-128 - 127].
Geralmente, caracteres não assinados são usados quando você não deseja um sinal. Isso fará a diferença ao fazer coisas como bits de deslocamento (shift estende o sinal) e outras coisas ao lidar com um char como um byte, em vez de usá-lo como um número.
citado do livro "the c programming laugage":
O qualificador signed
ou unsigned
pode ser aplicado a char ou a qualquer número inteiro. números não assinados são sempre positivos ou zero e obedecem às leis do módulo aritmético 2 ^ n, em que n é o número de bits no tipo. Assim, por exemplo, se caracteres são 8 bits, variáveis de caracteres não assinadas têm valores entre 0 e 255, enquanto caracteres assinados têm valores entre -128 e 127 (em uma máquina de complemento de dois). Se caracteres simples são assinados ou não é uma máquina independentes, mas os caracteres imprimíveis são sempre positivos.
signed char
e unsigned char
ambos representam 1 byte, mas eles têm intervalos diferentes.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
Em signed char
se considerarmos char letter = 'A'
, 'A' é representar binário de 65 em ASCII/Unicode
, Se 65 pode ser armazenado, -65 também podem ser armazenados. Não há valores binários negativos ASCII/Unicode
, pois não há necessidade de se preocupar com valores negativos.
Exemplo
#include <stdio.h>
int main()
{
signed char char1 = 255;
signed char char2 = -128;
unsigned char char3 = 255;
unsigned char char4 = -128;
printf("Signed char(255) : %d\n",char1);
printf("Unsigned char(255) : %d\n",char3);
printf("\nSigned char(-128) : %d\n",char2);
printf("Unsigned char(-128) : %d\n",char4);
return 0;
}
Resultado -:
Signed char(255) : -1
Unsigned char(255) : 255
Signed char(-128) : -128
Unsigned char(-128) : 128