Quelles plates-formes ont autre chose que des caractères 8 bits?

136

De temps en temps, quelqu'un sur SO fait remarquer que char(alias «octet») n'est pas nécessairement 8 bits .

Il semble que le 8 bits charsoit presque universel. J'aurais pensé que pour les plates-formes grand public, il est nécessaire d'avoir un 8 bits charpour assurer sa viabilité sur le marché.

À la fois maintenant et historiquement, quelles plates-formes utilisent un charqui n'est pas 8 bits, et pourquoi seraient-ils différents des 8 bits "normaux"?

Lors de l'écriture de code et de la réflexion sur la prise en charge multiplateforme (par exemple pour les bibliothèques à usage général), quel genre de considération vaut-il la peine de donner aux plates-formes non 8 bits char?

Dans le passé, j'ai rencontré des DSP Analog Devices pour char16 bits. Les DSP sont un peu une architecture de niche, je suppose. (Là encore, à l'époque l'assembleur codé à la main battait facilement ce que les compilateurs C disponibles pouvaient faire, donc je n'ai pas vraiment eu beaucoup d'expérience avec C sur cette plate-forme.)

Craig McQueen
la source
9
La série CDC Cyber ​​avait un encodage 6/12 bits. Les caractères les plus populaires étaient 6 bits. Les caractères restants utilisaient 12 bits.
Thomas Matthews
2
Le PDP-11 l'a cloué. La notion selon laquelle un caractère peut être encodé dans un char est sérieusement obsolète.
Hans Passant
7
"Le PDP-11 l'a cloué" - Vous voulez dire parce que C a d'abord été implémenté pour le PDP-11 avec 8 octets de bits? Mais C a ensuite été implémenté pour les machines Honeywell avec 9 octets. Voir K&R version 1. De plus, la question posée sur char (ie byte) et non sur character (un ou plusieurs octets encodant quelque chose qui n'a pas été posé).
Programmeur Windows
6
DEC-10 et DEC-20 avaient des mots de 36 bits. Cinq caractères ASCII 7 bits par mot étaient assez courants. En outre, six caractères de 6 bits ont été utilisés.
David R Tribble
3
@CraigMcQueen: Si je me souviens bien, CodeVision pour les microcontrôleurs Atmel permet de choisir la taille du caractère
vsz

Réponses:

80

charest également 16 bits sur les DSP Texas Instruments C54x, qui sont par exemple montés dans OMAP2. Il existe d'autres DSP avec 16 et 32 ​​bits char. Je pense que j'ai même entendu parler d'un DSP 24 bits, mais je ne me souviens pas quoi, alors peut-être que je l'ai imaginé.

Une autre considération est que les mandats POSIX CHAR_BIT == 8. Donc, si vous utilisez POSIX, vous pouvez le supposer. Si quelqu'un a besoin plus tard de porter votre code vers une quasi-implémentation de POSIX, cela se trouve juste pour avoir les fonctions que vous utilisez mais une taille différente char, c'est leur malchance.

En général, cependant, je pense qu'il est presque toujours plus facile de contourner le problème que d'y penser. Tapez simplementCHAR_BIT . Si vous voulez un type 8 bits exact, utilisez int8_t. Votre code échouera bruyamment à se compiler sur des implémentations qui n'en fournissent pas, au lieu d'utiliser silencieusement une taille à laquelle vous ne vous attendiez pas. À tout le moins, si je frappe un cas où j'avais une bonne raison de le supposer, alors je l'affirmerais.

Steve Jessop
la source
2
Les DSP TI C62xx et C64xx ont également des caractères 16 bits. (uint8_t n'est pas défini sur cette plate-forme.)
myron-semack
7
De nombreux DSP pour le traitement audio sont des machines 24 bits; les DSP BelaSigna d'On Semi (après avoir acheté AMI Semi); les DSP DSP56K / Symphony Audio de Freescale (après avoir été séparés de Motorola).
David Cary
2
@msemack C64xx a du matériel pour 8/16/32/40 et 8 bits char
user3528438
4
Plutôt que assert()(si c'est ce que vous vouliez dire), j'utiliserais #if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
Keith Thompson
1
@KeithThompson Y a-t-il une raison de ne pas utiliser static_assert()?
Qix - MONICA a été égaré le
37

Lors de l'écriture de code et de la réflexion sur la prise en charge multiplateforme (par exemple pour les bibliothèques à usage général), quelle sorte de considération vaut-il la peine de donner aux plates-formes avec un caractère non 8 bits?

Ce n'est pas tant qu'il «vaut la peine de prendre en considération» quelque chose, car il respecte les règles. En C ++, par exemple, la norme dit que tous les octets auront "au moins" 8 bits. Si votre code suppose que les octets ont exactement 8 bits, vous violez la norme.

Cela peut sembler idiot maintenant - " bien sûr, tous les octets ont 8 bits!", Je vous entends dire. Mais beaucoup de gens très intelligents se sont appuyés sur des hypothèses qui n'étaient pas des garanties, puis tout s'est cassé. L'histoire regorge de tels exemples.

Par exemple, la plupart des développeurs du début des années 90 ont supposé qu'un délai de synchronisation du processeur sans opération particulier prenant un nombre fixe de cycles nécessiterait une durée d'horloge fixe, car la plupart des processeurs grand public avaient à peu près la même puissance. Malheureusement, les ordinateurs sont devenus plus rapides très rapidement. Cela a engendré la montée en puissance des boîtes avec des boutons "Turbo" - dont le but, ironiquement, était de ralentir l'ordinateur afin que les jeux utilisant la technique de la temporisation puissent être joués à une vitesse raisonnable.


Un commentateur a demandé où dans la norme il était dit que char doit avoir au moins 8 bits. C'est dans la section 5.2.4.2.1 . Cette section définit CHAR_BITle nombre de bits dans la plus petite entité adressable et a une valeur par défaut de 8. Elle dit également:

Leurs valeurs définies par l'implémentation doivent être égales ou supérieures en grandeur (valeur absolue) à celles indiquées, avec le même signe.

Ainsi, tout nombre égal ou supérieur à 8 peut être remplacé par une implémentation dans CHAR_BIT.

John Feminella
la source
6
Je n'ai pas vu de bouton Turbo depuis au moins 20 ans - pensez-vous vraiment que c'est pertinent à la question?
Mark Ransom
29
@ Mark Ransom: C'est tout le problème. Les développeurs s'appuient souvent sur des hypothèses qui semblent être vraies pour le moment, mais qui sont beaucoup plus instables qu'elles ne le paraissent initialement. (Je ne peux pas compter le nombre de fois où j'ai commis cette erreur!) Le bouton Turbo devrait être un rappel douloureux de ne pas faire d'hypothèses inutiles, et certainement de ne pas faire d'hypothèses qui ne sont pas garanties par un standard de langue comme si elles l'étaient faits immuables.
John Feminella
1
Pourriez-vous préciser à placer dans C ++ Standard qui dit que le bye a au moins 8 bits? C'est une croyance commune, mais je n'ai personnellement pas réussi à la trouver dans la norme. La seule chose que j'ai trouvée dans Standard est de savoir quels caractères doivent être représentables, charil y en a plus de 64 mais moins de 128 donc 7 bits suffiraient.
Adam Badura
6
La section 18.2.2 invoque le standard C pour cela. Dans la norme C, il s'agit de la section 7.10, puis de la section 5.4.2.4.1. Page 22 de la norme C.
Programmeur Windows
2
Donc, d'autres réponses et commentaires mentionnent des machines avec des octets de 5 bits, 6 bits et 7 bits. Cela signifie-t-il que vous ne pouvez pas exécuter un programme C sur cette machine conforme à la norme?
Jerry Jeremiah
34

Les machines avec des architectures 36 bits ont des octets de 9 bits. Selon Wikipedia, les machines avec des architectures 36 bits comprennent:

  • Digital Equipment Corporation PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103 / 1103A / 1105/1100/2200,
R Samuel Klatchko
la source
7
Aussi des machines Honeywell, comme peut-être la deuxième machine sur laquelle C a été implémenté. Voir K&R version 1.
Programmeur Windows
5
En fait, le 10 décembre avait également des caractères de 6 bits - vous pouvez en regrouper 6 dans un mot de 36 bits (ancien programmeur du 10 décembre parlant)
2
Le DEC-20 utilisait cinq caractères ASCII 7 bits par mot 36 bits sur le TOPS-20 O / S.
David R Tribble
3
Cette blague a en fait été implémentée pour prendre en charge Unicode sur cette architecture.
Joshua
9
J'imagine que la raison pour laquelle octal a jamais été utilisé était parce que 3 chiffres octaux représentent parfaitement un octet de 9 bits, tout comme nous utilisons habituellement l'hexadécimal aujourd'hui parce que deux chiffres hexadécimaux représentent parfaitement un octet de 8 bits.
bames53 du
18

Quelques-uns dont je suis au courant:

  • DEC PDP-10: variable, mais le plus souvent des caractères 7 bits emballés 5 par mot 36 bits, ou bien 9 caractères bits, 4 par mot
  • Mainframes Control Data (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176, etc.) Caractères 6 bits, emballés 10 par mot de 60 bits.
  • Mainframes Unisys: 9 bits / octet
  • Windows CE: ne prend tout simplement pas en charge le type `char` - nécessite à la place wchar_t 16 bits
Jerry Coffin
la source
2
@ephemient: Je suis presque sûr qu'il y avait au moins un compilateur C (pré-standard) pour le PDP-10 / DecSystem 10 / DecSystem 20. Je serais très surpris par un compilateur C pour les mainframes CDC (ils étaient utilisé principalement pour le travail numérique, donc le compilateur Fortran était la grande chose là-bas). Je suis presque sûr que les autres ont des compilateurs C.
Jerry Coffin
3
Le compilateur Windows CE ne prend-il vraiment pas du tout en charge le chartype? Je sais que les bibliothèques système ne prenaient en charge que les versions à caractères larges des fonctions qui acceptent des chaînes, et qu'au moins certaines versions de WinCE ont supprimé les fonctions de chaîne ANSI telles que strlen, pour vous empêcher de gérer la chaîne de caractères. Mais n'avait-il vraiment pas du tout de type char? C'était quoi sizeof(TCHAR)? Quel type est retourné malloc? Comment le bytetype Java a-t-il été implémenté?
Steve Jessop
10
Windows CE prend en charge char, qui est un octet. Voir le commentaire de Craig McQueen sur la réponse de Richard Pennington. Les octets sont autant nécessaires dans Windows CE que partout ailleurs, quelle que soit leur taille partout ailleurs.
Programmeur Windows
2
Il y a (était?) Au moins deux implémentations de C pour le PDP-10: KCC et un port de gcc ( pdp10.nocrew.org/gcc ).
AProgrammer le
3
La norme C n'autorise pas les caractères 7 bits emballés à 5 par mot de 36 bits (comme vous l'avez mentionné pour le PDP-10), ni les caractères 6 bits, comme vous l'avez mentionné pour les mainframes Control Data. Voir parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Ken Bloom
15

Il n'existe pas de code totalement portable. :-)

Oui, il peut y avoir différentes tailles d'octets / caractères. Oui, il peut y avoir des implémentations C / C ++ pour les plates-formes avec des valeurs très inhabituelles de CHAR_BITet UCHAR_MAX. Oui, il est parfois possible d'écrire du code qui ne dépend pas de la taille du caractère.

Cependant, presque tous les codes réels ne sont pas autonomes. Par exemple, vous écrivez peut-être un code qui envoie des messages binaires au réseau (le protocole n'est pas important). Vous pouvez définir des structures contenant les champs nécessaires. Ensuite, vous devez le sérialiser. La simple copie binaire d'une structure dans un tampon de sortie n'est pas portable: généralement, vous ne connaissez ni l'ordre des octets de la plate-forme, ni l'alignement des membres de la structure, donc la structure ne contient que les données, mais ne décrit pas la façon dont les données doivent être sérialisées .

D'accord. Vous pouvez effectuer des transformations d'ordre des octets et déplacer les membres de la structure (par exemple uint32_tou similaire) memcpydans le tampon. Pourquoimemcpy ? Parce qu'il existe de nombreuses plates-formes sur lesquelles il n'est pas possible d'écrire en 32 bits (16 bits, 64 bits - aucune différence) lorsque l'adresse cible n'est pas correctement alignée.

Donc, vous avez déjà fait beaucoup pour atteindre la portabilité.

Et maintenant la dernière question. Nous avons un tampon. Les données qu'il contient sont envoyées au réseau TCP / IP. Un tel réseau suppose des octets de 8 bits. La question est: de quel type le tampon doit-il être? Si vos caractères sont 9 bits? S'ils sont 16 bits? 24? Peut-être que chaque caractère correspond à un octet de 8 bits envoyé au réseau et que seuls 8 bits sont utilisés? Ou peut-être que plusieurs octets de réseau sont emballés dans des caractères 24/16/9 bits? C'est une question et il est difficile de croire qu'il existe une réponse unique qui convienne à tous les cas. Beaucoup de choses dépendent de l'implémentation du socket pour la plate-forme cible.

Alors, de quoi je parle. Habituellement, le code peut être relativement facilement rendu portable dans une certaine mesure . Il est très important de le faire si vous prévoyez d'utiliser le code sur différentes plates-formes. Cependant, améliorer la portabilité au-delà de cette mesure est une chose qui demande beaucoup d'efforts et donne souvent peu , car le vrai code dépend presque toujours d'un autre code (implémentation de socket dans l'exemple ci-dessus). Je suis sûr que pour environ 90% du code, la capacité de fonctionner sur des plates-formes avec des octets autres que 8 bits est presque inutile, car il utilise un environnement lié à 8 bits. Vérifiez simplement la taille d'octet et effectuez une assertion de temps de compilation. Vous devrez presque sûrement réécrire beaucoup pour une plate-forme très inhabituelle.

Mais si votre code est hautement "autonome" - pourquoi pas? Vous pouvez l'écrire d'une manière qui autorise différentes tailles d'octets.

Ellioh
la source
4
Si l'on stocke un octet par unsigned charvaleur, il ne devrait y avoir aucun problème de portabilité à moins que le code n'utilise des astuces d'alias plutôt que des décalages pour convertir des séquences d'octets vers / à partir de types entiers plus grands. Personnellement, je pense que la norme C devrait définir des éléments intrinsèques pour emballer / décompresser des entiers à partir de séquences de types plus courts (le plus généralement char) stockant un nombre fixe de bits disponibles garantis par élément (8 par unsigned char, 16 par unsigned shortou 32 par unsigned long).
supercat
9

Il semble que vous puissiez toujours acheter un IM6100 (c'est-à-dire un PDP-8 sur puce) dans un entrepôt. C'est une architecture 12 bits.

dmckee --- chaton ex-modérateur
la source
9

De nombreuses puces DSP ont 16 ou 32 bits char. TI fabrique régulièrement de telles puces par exemple .

Alok Singhal
la source
5

Les langages de programmation C et C ++, par exemple, définissent byte comme "une unité de données adressable suffisamment grande pour contenir n'importe quel membre du jeu de caractères de base de l'environnement d'exécution" (clause 3.6 du standard C). Puisque le type de données intégral C char doit contenir au moins 8 bits (clause 5.2.4.2.1), un octet en C est au moins capable de contenir 256 valeurs différentes. Diverses implémentations de C et C ++ définissent un octet comme 8, 9, 16, 32 ou 36 bits

Extrait de http://en.wikipedia.org/wiki/Byte#History

Pas sûr des autres langues cependant.

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

Définit un octet sur cette machine comme étant de longueur variable

Petantik
la source
1
"Je ne suis pas sûr des autres langages" - historiquement, la plupart des langages permettaient à l'architecture de la machine de définir sa propre taille d'octet. En fait, historiquement, C a fait de même, jusqu'à ce que la norme fixe une limite inférieure à 8.
Programmeur Windows
4

La famille DEC PDP-8 avait un mot de 12 bits bien que vous utilisiez habituellement 8 bits ASCII pour la sortie (sur un télétype principalement). Cependant, il y avait aussi un code de caractères à 6 bits qui vous permettait d'encoder 2 caractères dans un seul mot de 12 bits.

PrgTrdr
la source
3

D'une part, les caractères Unicode sont plus longs que 8 bits. Comme quelqu'un l'a mentionné précédemment, la spécification C définit les types de données par leur taille minimale. Utilisation sizeofet les valeurs danslimits.h si vous souhaitez interroger vos types de données et découvrir exactement leur taille pour votre configuration et votre architecture.

Pour cette raison, j'essaie de m'en tenir aux types de données, comme uint16_tlorsque j'ai besoin d'un type de données d'une longueur de bits particulière.

Edit: Désolé, j'ai initialement mal lu votre question.

La spécification C indique qu'un charobjet est "suffisamment grand pour stocker n'importe quel membre du jeu de caractères d'exécution". limits.hrépertorie une taille minimale de 8 bits, mais la définition laisse la taille maximale d'un charouvert.

Ainsi, le a charest au moins aussi long que le caractère le plus grand de l'ensemble d'exécution de votre architecture (généralement arrondi à la limite de 8 bits la plus proche). Si votre architecture a des opcodes plus longs, votrechar taille peut être plus longue.

Historiquement, l'opcode de la plate-forme x86 faisait un octet de long, donc charétait initialement une valeur de 8 bits. Les plates-formes x86 actuelles prennent en charge les opcodes de plus d'un octet, mais la charlongueur est de 8 bits car c'est à cela que les programmeurs (et les grands volumes de code x86 existant) sont conditionnés.

Lorsque vous pensez à la prise en charge multiplateforme, tirez parti des types définis dans stdint.h. Si vous utilisez (par exemple) un uint16_t, alors vous pouvez être sûr que cette valeur est une valeur non signée 16 bits sur l' architecture tout, que ce soit qui correspond à valeur 16 bits à un char, short, intou autre chose. La plupart du travail acharné a déjà été effectué par les personnes qui ont écrit votre compilateur / bibliothèques standard.

Si vous avez besoin de connaître la taille exacte d'un charparce que vous effectuez une manipulation matérielle de bas niveau qui le nécessite, j'utilise généralement un type de données suffisamment grand pour contenir un charsur toutes les plates-formes prises en charge (généralement 16 bits suffisent) et j'exécute la valeur via une convert_to_machine_charroutine lorsque j'ai besoin de la représentation exacte de la machine. De cette façon, le code spécifique à la plate-forme est limité à la fonction d'interface et la plupart du temps, je peux utiliser un fichier normal uint16_t.

bta
la source
2
La question ne portait pas sur les caractères (qu'ils soient Unicode ou non). Il a posé des questions sur char, qui est un octet.
Programmeur Windows
1
De plus, le jeu de caractères d'exécution n'a rien à voir avec les opcodes, c'est le jeu de caractères utilisé lors de l'exécution, pensez aux compilateurs croisés.
ninjalj
«Historiquement, l'opcode de la plate-forme x86 faisait un octet de long»: quelle douceur. Historiquement , C a été développé sur un PDP-11 (1972), bien avant l'invention de x86 (1978).
Martin Bonner soutient Monica
3

quel genre de considération vaut-il la peine de donner aux plates-formes avec un caractère non 8 bits?

les nombres magiques se produisent par exemple lors du déplacement;

la plupart de ceux-ci peuvent être traités tout simplement en utilisant CHAR_BIT et par exemple UCHAR_MAX au lieu de 8 et 255 (ou similaire).

j'espère que votre implémentation les définit :)

ce sont les problèmes "courants" .....

un autre problème indirect est de dire que vous avez:

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

cela peut "seulement" prendre (dans le meilleur des cas) 24 bits sur une plate-forme, mais peut prendre par exemple 72 bits ailleurs .....

si chaque uchar contenait des "bit flags" et que chaque uchar n'avait que 2 bits ou flags "significatifs" que vous utilisiez actuellement, et que vous les organisiez seulement en 3 uchars pour "clarté", alors cela pourrait être relativement "plus gaspilleur" par exemple sur une plate-forme avec uchars 24 bits .....

rien que les champs de bits ne peuvent résoudre, mais ils ont d'autres choses à surveiller ...

dans ce cas, une seule énumération peut être un moyen d'obtenir le "plus petit" entier dont vous avez réellement besoin ...

peut-être pas un vrai exemple, mais des trucs comme ça me "mord" quand on porte / joue avec du code .....

juste le fait que si un uchar est trois fois plus grand que ce qui est "normalement" attendu, 100 de ces structures pourraient gaspiller beaucoup de mémoire sur certaines plates-formes ..... là où "normalement" ce n'est pas un gros problème .... .

donc les choses peuvent encore être "cassées" ou dans ce cas "gaspiller beaucoup de mémoire très rapidement" en raison de l'hypothèse qu'un uchar n'est "pas très gaspilleur" sur une plate-forme, par rapport à la RAM disponible, que sur une autre plate-forme ... ..

le problème peut être plus important, par exemple pour les ints également, ou pour d'autres types, par exemple, vous avez une structure qui a besoin de 15 bits, vous la collez donc dans un int, mais sur une autre plate-forme, un int est de 48 bits ou autre ... .

"normalement" vous pourriez le diviser en 2 uchars, mais par exemple avec un uchar 24 bits, vous n'en auriez besoin que d'un .....

donc une énumération pourrait être une meilleure solution "générique" ....

dépend de la façon dont vous accédez à ces bits :)

donc, il peut y avoir des "défauts de conception" qui leur viennent à l'esprit .... même si le code peut toujours fonctionner / fonctionner correctement quelle que soit la taille d'un uchar ou d'un uint ...

il y a des choses comme ça à surveiller, même s'il n'y a pas de "nombres magiques" dans votre code ...

j'espère que cela a du sens :)

dd ee
la source
1
...quelle? Pourquoi pensez-vous qu'il enumest susceptible d'être plus petit que les autres types natifs? Savez-vous qu'il utilise par défaut le même stockage que int? « vous avez une structure qui a besoin 15 bits, de sorte que vous tenez dans un int, mais sur une autre plate - forme est un entier 48 bits ou quoi que ..... » - donc #include <cstdint>et en faire un int16_tpour la meilleure chance de minimiser l' utilisation de bits . Je ne sais vraiment pas ce que vous pensiez dire parmi toutes ces ellipses.
underscore_d
1

Les ints étaient 16 bits (pdp11, etc.). Passer à des architectures 32 bits était difficile. Les gens vont mieux: presque personne ne suppose qu'un pointeur tiendra plus longtemps (vous n'avez pas raison?). Ou des décalages de fichiers, ou des horodatages, ou ...

Les caractères 8 bits sont déjà un peu anachroniques. Nous avons déjà besoin de 32 bits pour contenir tous les jeux de caractères du monde.

Richard Pennington
la source
2
Vrai. Le nom charest un peu étrange maintenant à l'époque Unicode. Je me soucie plus des unités 8 bits (octets) lorsque je traite des données binaires, par exemple le stockage de fichiers, les communications réseau. uint8_test plus utile.
Craig McQueen
3
Unicode n'a jamais eu besoin de 32 bits complets, en fait. Ils avaient initialement prévu 31 (voir le travail UTF-8 original), mais maintenant ils se contentent de seulement 21 bits . Ils ont probablement réalisé qu'ils ne pourraient plus imprimer le livre s'ils avaient réellement besoin des 31 bits: P
me22
2
@ me22, Unicode initialement prévu pour 16 bits. "Les caractères Unicode ont toujours une largeur de 16 bits, quelle que soit la langue ..." Unicode 1.0.0. unicode.org/versions/Unicode1.0.0/ch01.pdf .
Shannon Severance
1
L'ISO 10646 était à l'origine de 31 bits et Unicode a fusionné avec l'ISO 10646, il peut donc être bâclé de dire qu'Unicode était de 31 bits, mais ce n'est pas vraiment faux. Notez qu'ils n'impriment plus les tableaux de codes complets.
prosfilaes le