Quali piattaforme hanno qualcosa di diverso dal char a 8 bit?


136

Di tanto in tanto, qualcuno su SO sottolinea che char(aka 'byte') non è necessariamente 8 bit .

Sembra che 8 bit charsia quasi universale. Avrei pensato che per le piattaforme tradizionali, è necessario disporre di un 8 bit charper garantirne la fattibilità sul mercato.

Sia ora che storicamente, quali piattaforme usano un charnon 8 bit, e perché dovrebbero differire dai "normali" 8 bit?

Quando si scrive codice e si pensa al supporto multipiattaforma (ad es. Per librerie di uso generale), che tipo di considerazione vale la pena prestare alle piattaforme con non-8-bit char?

In passato mi sono imbattuto in alcuni DSP Analog Devices per i quali charè 16 bit. I DSP sono un po 'un'architettura di nicchia, suppongo. (D'altra parte, all'epoca l'assemblatore con codice manuale batteva facilmente ciò che i compilatori C disponibili potevano fare, quindi non ho avuto molta esperienza con C su quella piattaforma.)


9
La serie CDC Cyber ​​aveva una codifica a 6/12 bit. I personaggi più popolari erano 6 bit. I caratteri rimanenti hanno usato 12 bit.
Thomas Matthews,

2
Il PDP-11 l'ha inchiodato. L'idea che un personaggio possa essere codificato in un personaggio è seriamente obsoleta.
Hans Passant,

7
"Il PDP-11 l'ha inchiodato" - Intendi perché C è stato implementato per la prima volta per il PDP-11 con byte a 8 bit? Ma C è stato successivamente implementato per macchine Honeywell con byte a 9 bit. Vedi la versione K&R 1. Inoltre, la domanda posta sul carattere char (ovvero byte) non sul carattere (uno o più byte che codificano qualcosa di cui non è stato chiesto).
Programmatore di Windows,

6
DEC-10 e DEC-20 avevano parole a 36 bit. Cinque caratteri ASCII a 7 bit per parola erano abbastanza comuni. Sono stati utilizzati anche sei caratteri a 6 bit.
David R Tribble,

3
@CraigMcQueen: Se ricordo bene, CodeVision per i microcontrollori Atmel consente di scegliere la dimensione del carattere
vsz

Risposte:


80

charè anche a 16 bit sui DSP C54x di Texas Instruments, presentati ad esempio in OMAP2. Ci sono altri DSP là fuori con 16 e 32 bit char. Penso di aver persino sentito parlare di un DSP a 24 bit, ma non ricordo cosa, quindi forse l'ho immaginato.

Un'altra considerazione è che i mandati POSIX CHAR_BIT == 8. Quindi, se stai usando POSIX, puoi assumerlo. Se in seguito qualcuno ha bisogno di trasferire il tuo codice su un'implementazione prossima di POSIX, è proprio per questo che ha le funzioni che usi ma di dimensioni diverse char, è la loro sfortuna.

In generale, tuttavia, penso che sia quasi sempre più facile aggirare il problema piuttosto che pensarci. Basta digitare CHAR_BIT. Se si desidera un tipo esatto di 8 bit, utilizzare int8_t. Il tuo codice non riuscirà a compilare rumorosamente su implementazioni che non ne forniscono una, invece di utilizzare silenziosamente una dimensione che non ti aspettavi. Per lo meno, se avessi affrontato un caso in cui avevo una buona ragione per assumerlo, lo affermerei.


2
I DSP TI C62xx e C64xx hanno anche caratteri a 16 bit. (uint8_t non è definito su quella piattaforma.)
myron-semack

7
Molti DSP per l'elaborazione audio sono macchine a 24 bit; i DSP BelaSigna di On Semi (dopo aver acquistato AMI Semi); i DSP DSP56K / Symphony Audio di Freescale (dopo essere stati spinti fuori da Motorola).
David Cary,

2
@msemack C64xx ha hardware per 16/8/32/40 e 8 bit char
user3528438

4
Invece di assert()(se è quello che volevi dire), userei #if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
Keith Thompson il

1
@KeithThompson C'è qualche motivo per non usarlo static_assert()?
Qix - MONICA È STATA MISTREATA il

37

Quando si scrive codice e si pensa al supporto multipiattaforma (ad es. Per librerie di uso generale), che tipo di considerazione vale la pena prestare alle piattaforme con caratteri non a 8 bit?

Non è così tanto che "vale la pena prendere in considerazione" qualcosa in quanto sta giocando secondo le regole. In C ++, ad esempio, lo standard dice che tutti i byte avranno "almeno" 8 bit. Se il tuo codice presuppone che i byte contengano esattamente 8 bit, stai violando lo standard.

Ora può sembrare sciocco - " ovviamente tutti i byte hanno 8 bit!", Ti sento dire. Ma molte persone molto intelligenti hanno fatto affidamento su ipotesi che non erano garanzie, e poi tutto si è rotto. La storia è piena di tali esempi.

Ad esempio, la maggior parte degli sviluppatori degli inizi degli anni '90 ipotizzava che un particolare ritardo di temporizzazione della CPU non operativo che richiedesse un numero fisso di cicli avrebbe richiesto un tempo di clock fisso, poiché la maggior parte delle CPU di consumo erano all'incirca equivalenti in termini di potenza. Sfortunatamente, i computer sono diventati più veloci molto rapidamente. Ciò ha generato l'ascesa di scatole con pulsanti "Turbo" - il cui scopo, ironicamente, era quello di rallentare il computer in modo che i giochi usando la tecnica del ritardo potessero essere giocati a una velocità ragionevole.


Un commentatore ha chiesto dove nello standard si dice che char deve avere almeno 8 bit. È nella sezione 5.2.4.2.1 . Questa sezione definisce CHAR_BITil numero di bit nell'entità indirizzabile più piccola e ha un valore predefinito di 8. Dice anche:

I loro valori definiti dall'implementazione devono essere uguali o maggiori in grandezza (valore assoluto) a quelli mostrati, con lo stesso segno.

Quindi qualsiasi numero uguale a 8 o superiore è adatto per la sostituzione mediante un'implementazione in CHAR_BIT.


6
Non vedo un pulsante Turbo da almeno 20 anni - credi davvero che sia un problema per la domanda?
Mark Ransom,

29
@ Mark Ransom: questo è il punto. Gli sviluppatori spesso fanno affidamento su ipotesi che al momento sembrano essere vere, ma che sono molto più instabili di quanto appaiano inizialmente. (Non è possibile contare il numero di volte che ho fatto che errore!) Il pulsante Turbo dovrebbe essere un ricordo doloroso di non effettuare assunzioni inutili, e non certo di effettuare assunzioni che non sono garantiti da uno standard di lingua, come se fossero fatti immutabili.
John Feminella,

1
Potresti far notare che è inserito nello standard C ++ che dice che il ciao ha almeno 8 bit? È una convinzione comune, tuttavia personalmente non sono riuscito a trovarlo nello standard. L'unica cosa che ho trovato in Standard è che i personaggi devono essere rappresentabili in quanto charce ne sono più di 64 ma meno di 128 quindi 7 bit sarebbero sufficienti.
Adam Badura,

6
La sezione 18.2.2 invoca lo standard C per questo. Nello standard C è la sezione 7.10 e quindi la sezione 5.4.2.4.1. Pagina 22 nello standard C.
Programmatore di Windows,

2
Quindi altre risposte e commenti menzionano macchine con byte a 5 bit, 6 bit e 7 bit. Ciò significa che non è possibile eseguire un programma C su quella macchina conforme allo standard?
Jerry Jeremiah,

34

Le macchine con architetture a 36 bit hanno byte a 9 bit. Secondo Wikipedia, le macchine con architetture a 36 bit includono:

  • Digital Equipment Corporation PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103 / 1103A / 1105/1100/2200,

7
Anche macchine Honeywell, come forse la seconda macchina in cui è stata implementata la C. Vedi K&R versione 1.
Programmatore di Windows

5
In realtà, il dic-10 ha avuto anche caratteri 6-bit - si potrebbe Pack 6 di questi in una parola di 36 bit (ex-dic-10 programmatore parlante)

2
Il DEC-20 utilizzava cinque caratteri ASCII a 7 bit per parola a 36 bit su TOPS-20 O / S.
David R Tribble,

3
Quella battuta è stata effettivamente implementata per supportare Unicode su questa architettura.
Giosuè,

9
Immagino che la ragione per cui l'ottale sia mai stato effettivamente usato è perché 3 cifre ottali rappresentano ordinatamente un byte a 9 bit, proprio come oggi usiamo normalmente esadecimali perché due cifre esadecimali rappresentano ordinatamente un byte a 8 bit.
bames53,

18

Alcuni dei quali sono a conoscenza:

  • DEC PDP-10: caratteri variabili, ma il più delle volte a 7 bit impacchettati 5 per parola a 36 bit, oppure caratteri a 9 bit, 4 per parola
  • Mainframe di Control Data (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176 ecc.) Caratteri a 6 bit, impacchettati 10 per parola a 60 bit.
  • Mainframe Unisys: 9 bit / byte
  • Windows CE: semplicemente non supporta affatto il tipo `char` - richiede invece 16 bit wchar_t

2
@ephemient: Sono abbastanza sicuro che ci fosse almeno un compilatore C (pre-standard) per PDP-10 / DecSystem 10 / DecSystem 20. Sarei molto sorpreso da un compilatore C per i mainframe CDC (erano usato principalmente per il lavoro numerico, quindi il compilatore Fortran era la cosa più importante). Sono abbastanza sicuro che gli altri abbiano compilatori C.
Jerry Coffin,

3
Il compilatore Windows CE non supportava affatto il chartipo? So che le librerie di sistema supportavano solo le versioni wide char delle funzioni che accettano le stringhe e che almeno alcune versioni di WinCE hanno rimosso le funzioni della stringa ANSI come strlen, per impedirti di gestire la gestione delle stringhe char. Ma non aveva davvero un tipo di carattere? Che cosa era sizeof(TCHAR)? Che tipo ha restituito malloc? Come è stato byteimplementato il tipo Java ?
Steve Jessop,

10
Windows CE supporta char, che è un byte. Vedi il commento di Craig McQueen sulla risposta di Richard Pennington. I byte sono necessari tanto in Windows CE quanto ovunque, indipendentemente dalle dimensioni in cui si trovano ovunque.
Programmatore di Windows,

2
Ci sono (erano?) Almeno due implementazioni di C per il PDP-10: KCC e un porto di gcc ( pdp10.nocrew.org/gcc ).
Programmatore

3
Lo standard C non consentirebbe i caratteri a 7 bit impacchettati 5 per parola a 36 bit (come menzionato per il PDP-10), né consentirebbe i caratteri a 6 bit, come menzionato per i mainframe Control Data. Vedi parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Ken Bloom

15

Non esiste un codice completamente portatile. :-)

Sì, potrebbero esserci varie dimensioni di byte / caratteri. Sì, potrebbero esserci implementazioni C / C ++ per piattaforme con valori molto insoliti di CHAR_BITe UCHAR_MAX. Sì, a volte è possibile scrivere codice che non dipende dalla dimensione del carattere.

Tuttavia, quasi ogni codice reale non è autonomo. Ad esempio, potresti scrivere un codice che invia messaggi binari alla rete (il protocollo non è importante). È possibile definire strutture che contengono campi necessari. Di quanto devi serializzarlo. La semplice copia binaria di una struttura in un buffer di output non è portatile: generalmente non si conosce né l'ordine dei byte per la piattaforma, né l'allineamento dei membri della struttura, quindi la struttura contiene solo i dati, ma non descrive il modo in cui i dati devono essere serializzati .

Ok. È possibile eseguire trasformazioni dell'ordine dei byte e spostare i membri della struttura (ad esempio uint32_to simili) utilizzando memcpynel buffer. Perché memcpy? Perché ci sono molte piattaforme in cui non è possibile scrivere a 32 bit (16 bit, 64 bit - nessuna differenza) quando l'indirizzo di destinazione non è allineato correttamente.

Quindi, hai già fatto molto per raggiungere la portabilità.

E ora l'ultima domanda. Abbiamo un buffer. I dati da esso inviati vengono inviati alla rete TCP / IP. Tale rete assume byte a 8 bit. La domanda è: di che tipo dovrebbe essere il buffer? Se i tuoi caratteri sono a 9 bit? Se sono a 16 bit? 24? Forse ogni carattere corrisponde a un byte a 8 bit inviato alla rete e vengono utilizzati solo 8 bit? O forse più byte di rete sono impacchettati in caratteri a 24/16/9 bit? Questa è una domanda, ed è difficile credere che esista un'unica risposta adatta a tutti i casi. Molte cose dipendono dall'implementazione del socket per la piattaforma di destinazione.

Quindi, di cosa sto parlando. Di solito il codice può essere relativamente facilmente trasportabile in una certa misura . È molto importante farlo se si prevede di utilizzare il codice su piattaforme diverse. Tuttavia, migliorare la portabilità oltre tale misura è una cosa che richiede molto sforzo e spesso dà poco , poiché il codice reale dipende quasi sempre da altro codice (implementazione del socket nell'esempio sopra). Sono sicuro che per circa il 90% della capacità del codice di lavorare su piattaforme con byte diversi da 8 bit è quasi inutile, poiché utilizza un ambiente associato a 8 bit. Basta controllare la dimensione dei byte ed eseguire l'asserzione del tempo di compilazione. Quasi sicuramente dovrai riscrivere molto per una piattaforma molto insolita.

Ma se il tuo codice è altamente "autonomo" - perché no? Puoi scriverlo in un modo che consenta dimensioni di byte diverse.


4
Se si memorizza un ottetto per unsigned charvalore, non dovrebbero esserci problemi di portabilità a meno che il codice non usi trucchi di aliasing anziché turni per convertire sequenze di ottetti in / da tipi di numeri interi più grandi. Personalmente, penso che lo standard C dovrebbe definire i valori intrinseci per impacchettare / decomprimere numeri interi da sequenze di tipi più brevi (più in genere char) che memorizzano un numero fisso garantito disponibile di bit per articolo (8 per unsigned char, 16 per unsigned shorto 32 per unsigned long).
supercat



5

I linguaggi di programmazione C e C ++, ad esempio, definiscono il byte come "unità di dati indirizzabili abbastanza grande da contenere qualsiasi membro del set di caratteri di base dell'ambiente di esecuzione" (clausola 3.6 dello standard C). Poiché il tipo di dati integrale C char deve contenere almeno 8 bit (clausola 5.2.4.2.1), un byte in C è almeno in grado di contenere 256 valori diversi. Varie implementazioni di C e C ++ definiscono un byte come 8, 9, 16, 32 o 36 bit

Citato da http://en.wikipedia.org/wiki/Byte#History

Non sono sicuro di altre lingue però.

http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats

Definisce un byte su quella macchina come lunghezza variabile


1
"Non sono sicuro di altre lingue" - storicamente, la maggior parte delle lingue ha permesso all'architettura della macchina di definire la propria dimensione di byte. In realtà storicamente anche C, fino a quando lo standard non ha fissato un limite inferiore a 8.
Programmatore di Windows

4

La famiglia DEC PDP-8 aveva una parola a 12 bit sebbene di solito si usasse ASCII a 8 bit per l'output (principalmente su un tipo di Teletype). Tuttavia, c'era anche un codice di carattere a 6 bit che ti consentiva di codificare 2 caratteri in una singola parola a 12 bit.


3

Per uno, i caratteri Unicode sono più lunghi di 8 bit. Come qualcuno ha menzionato in precedenza, la specifica C definisce i tipi di dati in base alle loro dimensioni minime. Utilizzare sizeofe i valori in limits.hse si desidera interrogare i tipi di dati e scoprire esattamente quali dimensioni sono per la configurazione e l'architettura.

Per questo motivo, provo ad attenermi a tipi di dati come uint16_tquando ho bisogno di un tipo di dati di una determinata lunghezza di bit.

Modifica: scusa, inizialmente ho letto male la tua domanda.

La specifica C afferma che un charoggetto è "abbastanza grande da contenere qualsiasi membro del set di caratteri di esecuzione". limits.helenca una dimensione minima di 8 bit, ma la definizione lascia charaperta la dimensione massima .

Pertanto, a charè almeno lungo quanto il carattere più grande del set di esecuzione dell'architettura (in genere arrotondato per eccesso al limite di 8 bit più vicino). Se la tua architettura ha codici operativi più lunghi, le chardimensioni potrebbero essere più lunghe.

Storicamente, il codice operativo della piattaforma x86 era lungo un byte, quindi charinizialmente era un valore di 8 bit. Le attuali piattaforme x86 supportano i codici operativi più lunghi di un byte, ma charsono mantenuti a 8 bit di lunghezza poiché è quello a cui sono condizionati i programmatori (e i grandi volumi del codice x86 esistente).

Quando si pensa al supporto multipiattaforma, sfruttare i tipi definiti in stdint.h. Se si utilizza (ad esempio) un uint16_t, allora si può essere sicuri che questo valore è un valore a 16 bit senza segno su qualsiasi architettura, se corrispondente valore a 16 bit a una char, short, int, o qualcos'altro. Gran parte del duro lavoro è già stato fatto dalle persone che hanno scritto il tuo compilatore / librerie standard.

Se devi conoscere la dimensione esatta di a charperché stai eseguendo una manipolazione hardware di basso livello che lo richiede, di solito utilizzo un tipo di dati abbastanza grande da contenere un charsu tutte le piattaforme supportate (di solito 16 bit è sufficiente) ed eseguire il valore attraverso una convert_to_machine_charroutine quando ho bisogno della rappresentazione esatta della macchina. In questo modo, il codice specifico della piattaforma è limitato alla funzione di interfaccia e il più delle volte posso usare un normale uint16_t.


2
La domanda non riguardava i personaggi (Unicode o meno). Ha chiesto di char, che è un byte.
Programmatore di Windows,

1
Inoltre, il set di caratteri di esecuzione non ha nulla a che fare con i codici operativi, è il set di caratteri utilizzato durante l'esecuzione, si pensi ai cross-compilatori.
ninjalj,

"Storicamente, il codice operativo della piattaforma x86 era lungo un byte": che dolcezza. Storicamente , C è stato sviluppato su un PDP-11 (1972), molto prima dell'invenzione di x86 (1978).
Martin Bonner supporta Monica il

3

che tipo di considerazione vale la pena dare alle piattaforme con caratteri non a 8 bit?

si verificano numeri magici, ad es. quando si sposta;

la maggior parte di questi può essere gestita semplicemente usando CHAR_BIT e ad esempio UCHAR_MAX invece di 8 e 255 (o simili).

speriamo che la tua implementazione li definisca :)

quelli sono i problemi "comuni" .....

un altro problema indiretto è che hai:

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

questo potrebbe "solo" prendere (nel migliore dei casi) 24 bit su una piattaforma, ma potrebbe richiedere ad esempio 72 bit altrove .....

se ogni uchar contenesse "bit flags" e ogni uchar avesse solo 2 bit o flag "significativi" che stavi attualmente utilizzando, e li organizzassi solo in 3 uchar per "chiarezza", allora potrebbe essere relativamente "più dispendioso" ad es. una piattaforma con uchar a 24 bit .....

niente campi di bit non possono risolvere, ma hanno altre cose a cui fare attenzione ....

in questo caso, solo un singolo enum potrebbe essere un modo per ottenere il numero intero "più piccolo" di cui hai effettivamente bisogno ....

forse non è un vero esempio, ma cose come questa mi "mordono" durante il porting / giocando con un po 'di codice .....

solo il fatto che se un uchar è tre volte più grande di quello che è "normalmente" previsto, 100 di tali strutture potrebbero sprecare molta memoria su alcune piattaforme ..... dove "normalmente" non è un grosso problema .... .

quindi le cose possono ancora essere "rotte" o in questo caso "sprecare molta memoria molto rapidamente" a causa del presupposto che un uchar sia "non molto dispendioso" su una piattaforma, rispetto alla RAM disponibile, che su un'altra piattaforma ... ..

il problema potrebbe essere più evidente, ad esempio anche per gli ints o altri tipi, ad esempio hai una struttura che ha bisogno di 15 bit, quindi lo inserisci in un int, ma su un'altra piattaforma un int è di 48 bit o altro .... .

"normalmente" potresti dividerlo in 2 uchar, ma ad esempio con un uchar a 24 bit ne avresti bisogno solo uno .....

quindi un enum potrebbe essere una migliore soluzione "generica" ​​....

dipende da come stai accedendo a quei bit :)

quindi, potrebbero esserci "difetti di progettazione" che alzano la testa ... anche se il codice potrebbe ancora funzionare / funzionare bene indipendentemente dalle dimensioni di un uchar o uint ...

ci sono cose come queste a cui prestare attenzione, anche se non ci sono "numeri magici" nel tuo codice ...

spero che questo abbia senso :)


1
...che cosa? Perché pensi che enumsia probabilmente più piccolo di altri tipi nativi? Sei consapevole che per impostazione predefinita è lo stesso archivio di int? "hai una struttura che ha bisogno di 15 bit, quindi inseriscila in un int, ma su qualche altra piattaforma un int è 48 bit o altro ....." - quindi #include <cstdint>e rendilo una int16_tdelle migliori possibilità di minimizzare l'utilizzo dei bit . Non sono proprio sicuro di cosa pensassi di dire tra tutte quelle ellissi.
underscore_d

1

Ints erano 16 bit (pdp11, ecc.). Passare alle architetture a 32 bit è stato difficile. Le persone stanno migliorando: quasi nessuno suppone che un puntatore si adatti più a lungo (non è vero?). O offset di file, o timestamp, o ...

I caratteri a 8 bit sono già un po 'anacronistici. Abbiamo già bisogno di 32 bit per contenere tutti i set di caratteri del mondo.


2
Vero. Il nome charè un po 'strano ora ai giorni Unicode. Mi interessa di più sulle unità a 8 bit (ottetti) quando mi occupo di dati binari, ad esempio archiviazione di file, comunicazioni di rete. uint8_tè più utile.
Craig McQueen,

3
Unicode non ha mai avuto bisogno di ben 32 bit, in realtà. Inizialmente avevano pianificato 31 (vedi il lavoro originale UTF-8), ma ora sono contenti di soli 21 bit . Probabilmente si resero conto che non sarebbero stati più in grado di stampare il libro se avessero effettivamente avuto bisogno di tutti i 31 bit: P
me22

2
@ me22, Unicode inizialmente previsto per 16 bit. "I caratteri Unicode hanno una larghezza costante di 16 bit, indipendentemente dalla lingua ..." Unicode 1.0.0. unicode.org/versions/Unicode1.0.0/ch01.pdf .
Shannon Severance,

1
ISO 10646 era originariamente 31 bit e Unicode si fuse con ISO 10646, quindi potrebbe essere sciatto dire che Unicode era 31 bit, ma non è proprio falso. Nota che in realtà non stampano più le tabelle di codici complete.
prosfilaes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.