De vez em quando, alguém no SO indica que char
(também conhecido como 'byte') não é necessariamente 8 bits .
Parece que 8 bits char
é quase universal. Eu pensaria que, para plataformas convencionais, é necessário ter um 8-bit char
para garantir sua viabilidade no mercado.
Agora e historicamente, quais plataformas usam um char
que não é de 8 bits e por que diferem dos 8 bits "normais"?
Ao escrever código e pensar no suporte de plataforma cruzada (por exemplo, para bibliotecas de uso geral), que tipo de consideração vale a pena dar a plataformas com bit não de 8 bits char
?
No passado, encontrei alguns DSPs de dispositivos analógicos, dos quais char
16 bits. Os DSPs são um pouco de uma arquitetura de nicho, suponho. (Então, novamente, na época, o montador codificado à mão superava facilmente o que os compiladores C disponíveis podiam fazer, então eu realmente não tive muita experiência com o C nessa plataforma.)
fonte
Respostas:
char
também é de 16 bits nos Texas Instruments C54x DSPs, que apareceram, por exemplo, no OMAP2. Existem outros DSPs por aí com 16 e 32 bitschar
. Acho que ouvi falar de um DSP de 24 bits, mas não me lembro o quê, então talvez eu tenha imaginado.Outra consideração é que o POSIX exige
CHAR_BIT == 8
. Portanto, se você estiver usando o POSIX, poderá assumi-lo. Se alguém mais tarde precisar portar seu código para uma quase implementação do POSIX, isso só tem as funções que você usa, mas com um tamanho diferentechar
, isso é uma má sorte.Em geral, porém, acho que quase sempre é mais fácil solucionar o problema do que pensar sobre ele. Apenas digite
CHAR_BIT
. Se você deseja um tipo exato de 8 bits, useint8_t
. Seu código falhará ao compilar em implementações que não fornecem uma, em vez de usar silenciosamente um tamanho que você não esperava. No mínimo, se eu atingisse um caso em que tivesse um bom motivo para assumi-lo, eu o afirmaria.fonte
assert()
(se é isso que você quis dizer), eu usaria#if CHAR_BIT != 8
...#error "I require CHAR_BIT == 8"
...#endif
static_assert()
?Não é tanto que "vale a pena considerar" algo que está sendo cumprido pelas regras. Em C ++, por exemplo, o padrão diz que todos os bytes terão "pelo menos" 8 bits. Se o seu código assume que os bytes têm exatamente 8 bits, você está violando o padrão.
Isso pode parecer bobagem agora - "é claro que todos os bytes têm 8 bits!", Ouvi você dizer. Mas muitas pessoas muito inteligentes confiaram em suposições que não eram garantias, e então tudo quebrou. A história está repleta de exemplos.
Por exemplo, a maioria dos desenvolvedores do início dos anos 90 assumiu que um atraso de temporização da CPU não operacional em um número fixo de ciclos levaria uma quantidade fixa de tempo, porque a maioria das CPUs consumidoras era aproximadamente equivalente em energia. Infelizmente, os computadores ficaram mais rápidos muito rapidamente. Isso gerou o surgimento de caixas com os botões "Turbo" - cujo objetivo, ironicamente, era desacelerar o computador para que os jogos que usam a técnica de atraso de tempo pudessem ser jogados a uma velocidade razoável.
Um comentarista perguntou onde, no padrão, diz que char deve ter pelo menos 8 bits. Está na seção 5.2.4.2.1 . Esta seção define
CHAR_BIT
o número de bits na menor entidade endereçável e possui um valor padrão de 8. Ele também diz:Portanto, qualquer número igual a 8 ou superior é adequado para substituição por uma implementação no
CHAR_BIT
.fonte
char
pois existem mais de 64 deles, mas menos de 128 a 7 bits seria suficiente.Máquinas com arquiteturas de 36 bits possuem bytes de 9 bits. Segundo a Wikipedia, máquinas com arquiteturas de 36 bits incluem:
fonte
Alguns dos quais estou ciente:
fonte
char
tipo? Eu sei que as bibliotecas do sistema suportam apenas as versões amplas de caracteres de funções que usam seqüências de caracteres, e que pelo menos algumas versões do WinCE removeram as funções de seqüência de caracteres ANSI como strlen, para impedi-lo de manipular caracteres. Mas realmente não tinha um tipo de caractere? O que foisizeof(TCHAR)
? Que tipo de malloc retornou? Como obyte
tipo Java foi implementado?Não existe um código completamente portátil. :-)
Sim, pode haver vários tamanhos de bytes / caracteres. Sim, pode haver implementações de C / C ++ para plataformas com valores altamente incomuns de
CHAR_BIT
eUCHAR_MAX
. Sim, às vezes é possível escrever código que não depende do tamanho do caractere.No entanto, quase todo código real não é autônomo. Por exemplo, você pode estar escrevendo um código que envia mensagens binárias para a rede (o protocolo não é importante). Você pode definir estruturas que contêm campos necessários. Do que você precisa serializá-lo. A cópia binária de uma estrutura em um buffer de saída não é portátil: geralmente você não conhece a ordem dos bytes da plataforma, nem o alinhamento dos membros da estrutura; portanto, a estrutura retém os dados, mas não descreve a maneira como os dados devem ser serializados. .
Está bem. Você pode executar transformações de ordem de bytes e mover os membros da estrutura (por exemplo,
uint32_t
ou similares) usandomemcpy
o buffer. Por quememcpy
? Como existem muitas plataformas nas quais não é possível gravar 32 bits (16 bits, 64 bits - sem diferença) quando o endereço de destino não está alinhado corretamente.Então, você já fez muito para alcançar a portabilidade.
E agora a pergunta final. Nós temos um buffer. Os dados dele são enviados para a rede TCP / IP. Essa rede assume bytes de 8 bits. A questão é: de que tipo o buffer deve ser? Se seus caracteres são de 9 bits? Se eles são de 16 bits? 24? Talvez cada caractere corresponda a um byte de 8 bits enviado à rede, e apenas 8 bits são usados? Ou talvez vários bytes de rede sejam compactados em caracteres de 24/16/9 bits? Essa é uma pergunta, e é difícil acreditar que exista uma única resposta que sirva para todos os casos. Muitas coisas dependem da implementação do soquete para a plataforma de destino.
Então, o que eu estou falando. Normalmente, o código pode ser relativamente facilmente tornado portátil até certo ponto . É muito importante fazer isso se você espera usar o código em plataformas diferentes. No entanto, melhorar a portabilidade além dessa medida é algo que exige muito esforço e geralmente oferece pouco , pois o código real quase sempre depende de outro código (implementação de soquete no exemplo acima). Estou certo de que cerca de 90% da capacidade do código de trabalhar em plataformas com bytes diferentes de 8 bits é quase inútil, pois usa um ambiente vinculado a 8 bits. Basta verificar o tamanho do byte e executar a asserção do tempo de compilação. Você quase certamente terá que reescrever muito para uma plataforma altamente incomum.
Mas se o seu código é altamente "independente" - por que não? Você pode escrevê-lo de uma maneira que permita tamanhos diferentes de bytes.
fonte
unsigned char
valor, não deve haver problemas de portabilidade, a menos que o código use truques de alias em vez de turnos para converter seqüências de octetos para / de tipos inteiros maiores. Pessoalmente, acho que o padrão C deve definir intrínsecos para empacotar / descompactar números inteiros de sequências de tipos mais curtos (geralmentechar
) armazenando um número fixo garantido de bits disponíveis por item (8 porunsigned char
, 16 porunsigned short
ou 32 porunsigned long
).Parece que você ainda pode comprar um IM6100 (ou seja, um PDP-8 em um chip) de um armazém. Essa é uma arquitetura de 12 bits.
fonte
Muitos chips DSP possuem 16 ou 32 bits
char
. A TI faz rotineiramente esses chips, por exemplo .fonte
Citado em http://en.wikipedia.org/wiki/Byte#History
Não tenho certeza sobre outros idiomas.
http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats
Define um byte nessa máquina como comprimento variável
fonte
A família DEC PDP-8 tinha uma palavra de 12 bits, embora normalmente você usasse ASCII de 8 bits para saída (principalmente em um Teletype). No entanto, havia também um código de 6 bits que permitia codificar 2 caracteres em uma única palavra de 12 bits.
fonte
Por um lado, os caracteres Unicode têm mais de 8 bits. Como alguém mencionado anteriormente, a especificação C define os tipos de dados pelo tamanho mínimo. Use
sizeof
e os valores emlimits.h
se desejar interrogar seus tipos de dados e descobrir exatamente qual o tamanho deles para sua configuração e arquitetura.Por esse motivo, tento manter tipos de dados como
uint16_t
quando preciso de um tipo de dado com um comprimento de bit específico.Edit: Desculpe, inicialmente eu li errado sua pergunta.
A especificação C diz que um
char
objeto é "grande o suficiente para armazenar qualquer membro do conjunto de caracteres de execução".limits.h
lista um tamanho mínimo de 8 bits, mas a definição deixa o tamanho máximo de umchar
aberto.Portanto, o a
char
é pelo menos o maior caractere do conjunto de execução da sua arquitetura (normalmente arredondado para o limite de 8 bits mais próximo). Se sua arquitetura tiver códigos de operação mais longos, seuchar
tamanho poderá ser maior.Historicamente, o código de operação da plataforma x86 tinha um byte de comprimento,
char
inicialmente um valor de 8 bits. As plataformas x86 atuais suportam opcodes com mais de um byte, mas ochar
tamanho é mantido em 8 bits, pois é para isso que os programadores (e os grandes volumes do código x86 existente) estão condicionados.Ao pensar em suporte multiplataforma, aproveite os tipos definidos em
stdint.h
. Se você usa (por exemplo) um uint16_t, então você pode ter certeza que este valor é um valor de 16 bits sem sinal em qualquer arquitectura, quer que corresponde valor de 16 bits para umchar
,short
,int
, ou qualquer outra coisa. A maior parte do trabalho árduo já foi realizada pelas pessoas que escreveram suas bibliotecas de compilador / padrão.Se você precisa saber o tamanho exato de um
char
porque está fazendo alguma manipulação de hardware de baixo nível que exige isso, normalmente uso um tipo de dados que é grande o suficiente para armazenarchar
em todas as plataformas suportadas (geralmente 16 bits é suficiente) e executar o valor através de umaconvert_to_machine_char
rotina quando eu preciso da representação exata da máquina. Dessa forma, o código específico da plataforma está confinado à função de interface e na maioria das vezes eu posso usar um normaluint16_t
.fonte
números mágicos ocorrem, por exemplo, ao mudar;
a maioria deles pode ser tratada simplesmente usando CHAR_BIT e, por exemplo, UCHAR_MAX em vez de 8 e 255 (ou similar).
espero que sua implementação os defina :)
esses são os problemas "comuns" ...
Outra questão indireta é dizer que você tem:
isso pode "apenas" levar (na melhor das hipóteses) 24 bits em uma plataforma, mas pode levar, por exemplo, 72 bits em outro lugar .....
se cada uchar continha "sinalizadores de bits" e cada uchar tinha apenas 2 bits ou sinalizações "significativos" que você estava usando no momento, e você os organizou em apenas 3 uchars para "clareza", pode ser relativamente "mais inútil", por exemplo, uma plataforma com uchars de 24 bits .....
nada que os campos de bits não possam resolver, mas eles têm outras coisas a observar ....
Nesse caso, apenas uma enumeração única pode ser uma maneira de obter o número inteiro "menor" que você realmente precisa ....
talvez não seja um exemplo real, mas coisas como essa "me mordem" ao portar / jogar com algum código .....
apenas o fato de que se um uchar é três vezes maior do que o que "normalmente" é esperado, 100 dessas estruturas podem desperdiçar muita memória em algumas plataformas ..... onde "normalmente" não é grande coisa ... .
para que as coisas ainda possam ser "quebradas" ou, neste caso, "desperdiçar muita memória muito rapidamente" devido à suposição de que um uchar "não é muito desperdício" em uma plataforma, em relação à RAM disponível, do que em outra plataforma ... ..
o problema pode ser mais proeminente, por exemplo, para ints também ou outros tipos, por exemplo, você tem alguma estrutura que precisa de 15 bits, então você o coloca em um int, mas em outra plataforma um int é de 48 bits ou o que for ... .
"normalmente", você pode dividi-lo em 2 uchars, mas, por exemplo, com um uchar de 24 bits, você precisará apenas de um .....
então um enum pode ser uma solução "genérica" melhor ....
depende de como você está acessando esses bits :)
portanto, pode haver "falhas de design" que empinam a cabeça ... mesmo que o código ainda funcione / corra bem, independentemente do tamanho de um uchar ou uint ...
há coisas assim a serem observadas, mesmo que não haja "números mágicos" em seu código ...
espero que isso faça sentido :)
fonte
enum
provavelmente é menor que outros tipos nativos? Você sabe que o padrão é o mesmo armazenamento queint
? "você tem alguma estrutura que precisa de 15 bits, então você a coloca em um int, mas em alguma outra plataforma um int é de 48 bits ou o que for ....." - portanto,#include <cstdint>
faça deleint16_t
a melhor chance de minimizar o uso de bits . Eu realmente não tenho certeza do que você pensou que estava dizendo entre todas essas elipses.entradas costumavam ter 16 bits (pdp11, etc.). Ir para arquiteturas de 32 bits foi difícil. As pessoas estão melhorando: dificilmente alguém assume que um ponteiro caberá mais tempo (você não está certo?). Ou compensações de arquivo, registros de data e hora ou ...
Caracteres de 8 bits já são um tanto anacronismo. Já precisamos de 32 bits para armazenar todos os conjuntos de caracteres do mundo.
fonte
char
é um pouco singular agora em dias Unicode. Eu me preocupo mais com as unidades de 8 bits (octetos) ao lidar com dados binários, por exemplo, armazenamento de arquivos, comunicações em rede.uint8_t
é mais útil