Quais plataformas têm algo diferente de char de 8 bits?

136

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 charpara garantir sua viabilidade no mercado.

Agora e historicamente, quais plataformas usam um charque 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 char16 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.)

Craig McQueen
fonte
9
A série CDC Cyber ​​tinha uma codificação de 6/12 bits. Os personagens mais populares foram 6 bits. Os caracteres restantes usavam 12 bits.
Thomas Matthews
2
O PDP-11 acertou em cheio. A noção de que um personagem pode ser codificado em um caractere é seriamente obsoleta.
Hans Passant
7
"O PDP-11 acertou em cheio" - Você quer dizer que o C foi implementado pela primeira vez no PDP-11 com bytes de 8 bits? Mas C foi implementado em seguida para máquinas Honeywell com 9 bits de bytes. Consulte a versão 1. da K&R. Além disso, a pergunta feita sobre char (ou seja, byte) não é sobre caractere (um ou mais bytes que codificam algo que não foi perguntado).
Programador Windows
6
DEC-10 e DEC-20 tinham palavras de 36 bits. Cinco caracteres ASCII de 7 bits por palavra eram bastante comuns. Também foram utilizados seis caracteres de 6 bits.
David R Tribble
3
@CraigMcQueen: Se bem me lembro, Codevision para microcontroladores Atmel permite um escolher o tamanho do caractere
vsz

Respostas:

80

chartambém é de 16 bits nos Texas Instruments C54x DSPs, que apareceram, por exemplo, no OMAP2. Existem outros DSPs por aí com 16 e 32 bits char. 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 diferente char, 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, use int8_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.

Steve Jessop
fonte
2
Os DSPs TI C62xx e C64xx também possuem caracteres de 16 bits. (uint8_t não está definido nessa plataforma).
myron-semack 20/01
7
Muitos DSPs para processamento de áudio são máquinas de 24 bits; os DSPs BelaSigna da On Semi (depois que compraram a AMI Semi); o dsp56k / Symphony áudio DSPs da Freescale (depois de terem sido desmembrada da Motorola).
22812 David Cary
2
@msemack C64xx tem hardware para 8/16/32/40, e 8 bits de char
user3528438
4
Ao invés de assert()(se é isso que você quis dizer), eu usaria #if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
Keith Thompson
1
@KeithThompson Existe alguma razão para não usar static_assert()?
Qix - MONICA FOI ERRADA
37

Ao escrever código e pensar no suporte a várias plataformas (por exemplo, para bibliotecas de uso geral), que tipo de consideração vale a pena prestar a plataformas com caracteres que não são de 8 bits?

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_BITo número de bits na menor entidade endereçável e possui um valor padrão de 8. Ele também diz:

Seus valores definidos para implementação devem ser iguais ou superiores em magnitude (valor absoluto) aos mostrados, com o mesmo sinal.

Portanto, qualquer número igual a 8 ou superior é adequado para substituição por uma implementação no CHAR_BIT.

John Feminella
fonte
6
Não vejo um botão Turbo há pelo menos 20 anos - você realmente acha que é pertinente à pergunta?
Mark Ransom
29
@ Mark Ransom: Esse é o ponto. Os desenvolvedores costumam confiar em suposições que parecem verdadeiras no momento, mas que são muito mais instáveis ​​do que parecem inicialmente. (Não é possível contar o número de vezes que cometi esse erro!) O botão Turbo deve ser um lembrete doloroso para não fazer suposições desnecessárias e certamente não fazer suposições que não são garantidas por um padrão de idioma como se fossem fatos imutáveis.
John Janella
1
Você poderia apontar para colocar no C ++ Standard que diz que o bye tem pelo menos 8 bits? É uma crença comum, porém eu pessoalmente não consegui encontrá-la no Padrão. A única coisa que encontrei no Standard é que caracteres devem ser representáveis, charpois existem mais de 64 deles, mas menos de 128 a 7 bits seria suficiente.
Adam Badura
6
A Seção 18.2.2 chama o padrão C para ele. No padrão C, é a seção 7.10 e, em seguida, a seção 5.4.2.4.1. Página 22 no padrão C.
Programador Windows
2
Outras respostas e comentários mencionam máquinas com bytes de 5, 6 e 7 bits. Isso significa que você não pode executar um programa C nessa máquina que esteja em conformidade com o padrão?
Jerry Jeremiah
34

Máquinas com arquiteturas de 36 bits possuem bytes de 9 bits. Segundo a Wikipedia, máquinas com arquiteturas de 36 bits incluem:

  • Digital Equipment Corporation PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103 / 1103A / 1105/1100/2200,
R Samuel Klatchko
fonte
7
Também máquinas da Honeywell, como talvez a segunda máquina em que C foi implementada. Veja K&R versão 1.
Programador Windows
5
Na verdade, o Dec-10 teve também caracteres de 6 bits - você poderia embalar 6 destes em uma palavra de 36 bits (ex-Dez-10 programador falar)
2
O DEC-20 usou cinco caracteres ASCII de 7 bits por palavra de 36 bits no TOPS-20 O / S.
precisa saber é o seguinte
3
Essa piada foi realmente implementada para dar suporte ao Unicode nessa arquitetura.
Joshua
9
Imagino que a razão pela qual octal tenha sido realmente usada foi porque três dígitos octais representam ordenadamente um byte de 9 bits, assim como normalmente usamos hoje hexadecimal, porque dois dígitos hexadecimais representam perfeitamente um byte de 8 bits.
bames53
18

Alguns dos quais estou ciente:

  • DEC PDP-10: variável, mas na maioria das vezes caracteres de 7 bits compactados 5 por palavra de 36 bits ou caracteres de 9 bits, 4 por palavra
  • Mainframes dos dados de controle (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176 etc.) Caracteres de 6 bits, compactados 10 por palavra de 60 bits.
  • Mainframes da Unisys: 9 bits / byte
  • Windows CE: simplesmente não suporta o tipo `char` - requer 16-bit wchar_t
Jerry Coffin
fonte
2
@ ephemient: Tenho certeza de que havia pelo menos um compilador C (pré-padrão) para o PDP-10 / DecSystem 10 / DecSystem 20. Eu ficaria muito surpreso com um compilador C para os mainframes do CDC (eles eram usado principalmente para trabalhos numéricos, então o compilador Fortran foi a grande coisa lá). Tenho certeza de que os outros têm compiladores C.
Jerry Coffin
3
O compilador Windows CE realmente não suportava o chartipo? 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 foi sizeof(TCHAR)? Que tipo de malloc retornou? Como o bytetipo Java foi implementado?
Steve Jessop
10
Windows CE suporta char, que é um byte. Veja o comentário de Craig McQueen na resposta de Richard Pennington. Os bytes são necessários tanto no Windows CE quanto em qualquer outro lugar, independentemente de tamanhos em qualquer outro lugar.
Programador Windows
2
Existem (houve?) Pelo menos duas implementações de C para o PDP-10: KCC e uma porta do gcc ( pdp10.nocrew.org/gcc ).
APROGRAMADOR
3
O padrão C não permitia caracteres de 7 bits com 5 por palavra de 36 bits (como você mencionou para o PDP-10), nem caracteres de 6 bits, como mencionado nos mainframes dos Dados de Controle. Veja parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Ken Bloom
15

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_BITe UCHAR_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_tou similares) usando memcpyo buffer. Por que memcpy? 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.

Ellioh
fonte
4
Se alguém armazena um octeto por unsigned charvalor, 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 (geralmente char) armazenando um número fixo garantido de bits disponíveis por item (8 por unsigned char, 16 por unsigned shortou 32 por unsigned long).
Supercat
9

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.

dmckee --- gatinho ex-moderador
fonte
9

Muitos chips DSP possuem 16 ou 32 bits char. A TI faz rotineiramente esses chips, por exemplo .

Alok Singhal
fonte
5

As linguagens de programação C e C ++, por exemplo, definem byte como "unidade de dados endereçável, grande o suficiente para conter qualquer membro do conjunto de caracteres básico do ambiente de execução" (seção 3.6 do padrão C). Como o tipo de dados integral C char deve conter pelo menos 8 bits (seção 5.2.4.2.1), um byte em C é pelo menos capaz de conter 256 valores diferentes. Várias implementações de C e C ++ definem um byte como 8, 9, 16, 32 ou 36 bits

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

petantik
fonte
1
"Não tenho certeza sobre outros idiomas" - historicamente, a maioria dos idiomas permitia que a arquitetura da máquina definisse seu próprio tamanho de byte. Na verdade, historicamente, o fez C, até que o padrão estabeleceu um limite inferior em 8.
Programador Windows
4

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.

PrgTrdr
fonte
3

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 sizeofe os valores em limits.hse 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_tquando 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 charobjeto é "grande o suficiente para armazenar qualquer membro do conjunto de caracteres de execução". limits.hlista um tamanho mínimo de 8 bits, mas a definição deixa o tamanho máximo de um charaberto.

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, seu chartamanho poderá ser maior.

Historicamente, o código de operação da plataforma x86 tinha um byte de comprimento, charinicialmente um valor de 8 bits. As plataformas x86 atuais suportam opcodes com mais de um byte, mas o chartamanho é 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 um char, 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 charporque 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 armazenar charem todas as plataformas suportadas (geralmente 16 bits é suficiente) e executar o valor através de uma convert_to_machine_charrotina 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 normal uint16_t.

bta
fonte
2
A pergunta não perguntou sobre caracteres (Unicode ou não). Ele perguntou sobre char, que é um byte.
Programador Windows
1
Além disso, o conjunto de caracteres de execução não tem nada a ver com opcodes, é o conjunto de caracteres usado na execução, pense em compiladores cruzados.
Njalj 08/07
"Historicamente, o código de operação da plataforma x86 tinha um byte de comprimento": que doce. Historicamente , o C foi desenvolvido em um PDP-11 (1972), muito antes da invenção do x86 (1978).
Martin Bonner apoia Monica
3

que tipo de consideração vale a pena dar a plataformas com caracteres que não são de 8 bits?

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:

struct xyz {
   uchar baz;
   uchar blah;
   uchar buzz; 
}

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 :)

dd ee
fonte
1
...o que? Por que você acha que enumprovavelmente é menor que outros tipos nativos? Você sabe que o padrão é o mesmo armazenamento que int? "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 dele int16_ta 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.
Sublinhado_
1

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.

Richard Pennington
fonte
2
Verdade. O nome 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
Craig McQueen
3
O Unicode nunca precisou de 32 bits completos, na verdade. Eles originalmente planejavam 31 (veja o trabalho UTF-8 original), mas agora estão satisfeitos com apenas 21 bits . Eles provavelmente perceberam que não seria capaz de imprimir o livro mais se eles realmente necessários todos os 31 bits: P
ME22
2
@ me22, o Unicode originalmente planejado para 16 bits. "Os caracteres Unicode têm consistentemente 16 bits de largura, independentemente do idioma ..." Unicode 1.0.0. unicode.org/versions/Unicode1.0.0/ch01.pdf .
Shannon Severance
1
O ISO 10646 era originalmente de 31 bits e o Unicode foi mesclado com o ISO 10646; portanto, pode ser desleixado dizer que o Unicode era de 31 bits, mas não é realmente falso. Observe que eles realmente não imprimem mais as tabelas de códigos completas.
prosfilaes 24/01