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

De temps en temps, quelqu’un sur SO fait remarquer que le caractère (aka «octet») n’est pas nécessairement de 8 bits .

Il semble que le caractère 8 bits soit presque universel. J’aurais pensé que pour les plateformes classiques, il est nécessaire d’avoir un caractère de 8 bits pour assurer sa viabilité sur le marché.

Aujourd’hui et historiquement, quelles plates-formes utilisent un caractère qui n’est pas de 8 bits et pourquoi diffèrent-elles des 8 bits “normaux”?

Lorsque vous écrivez du code et que vous pensez à la prise en charge multi-plateforme (par exemple pour les bibliothèques à usage général), quel type de considération est-il utile de donner aux plates-formes avec des caractères non-8 bits?

Dans le passé, j’ai rencontré des DSP Analog Devices dont le caractère est de 16 bits. Je suppose que les DSP sont une architecture de niche. (Encore une fois, à ce moment-là, l’assembleur codé à la main dépassait facilement les capacités des compilateurs C disponibles, donc je n’avais pas vraiment beaucoup d’expérience avec C sur cette plateforme.)

char est également 16 bits sur les DSP Texas Instruments C54x, qui sont apparus par exemple dans OMAP2. Il existe d’autres DSP avec des caractères de 16 et 32 ​​bits. Je pense que j’ai même entendu parler d’un DSP 24 bits, mais je ne me souviens plus de quoi, alors je l’ai peut-être imaginé.

Une autre considération est que POSIX oblige CHAR_BIT == 8 . Donc, si vous utilisez POSIX, vous pouvez l’assumer. Si quelqu’un doit plus tard porter votre code dans une quasi-implémentation de POSIX, ce qui se passe comme si vous aviez les fonctions que vous utilisez mais un caractère de taille différente, c’est leur mauvaise chance.

En général, je pense qu’il est presque toujours plus facile de contourner le problème que d’y penser. Tapez simplement CHAR_BIT . Si vous voulez un type exact de 8 bits, utilisez int8_t . Votre code ne comstackra pas brusquement les implémentations qui n’en fournissent pas, au lieu d’utiliser silencieusement une taille inattendue. À tout le moins, si je frappe un cas où j’avais une bonne raison de l’assumer, alors je l’affirmerais.

Lorsque vous écrivez du code et que vous pensez à la prise en charge multi-plateforme (par exemple pour les bibliothèques à usage général), quel type de considération est-il utile de donner aux plates-formes avec des caractères non-8 bits?

Ce n’est pas tellement que cela vaut la peine de prendre en considération quelque chose tel que le font les règles. En C ++, par exemple, la norme stipule 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 personnes très intelligentes se sont appuyées sur des suppositions qui n’étaient pas des garanties, puis tout a cédé. L’histoire est remplie de tels exemples.

Par exemple, la plupart des développeurs du début des années 90 supposaient qu’un délai de processeur particulier sans processeur nécessitant un nombre de cycles fixe prendrait une durée d’horloge fixe, car la plupart des processeurs grand public étaient à peu près équivalents. Malheureusement, les ordinateurs sont devenus plus rapides très rapidement. Cela a donné lieu à la montée en puissance des boîtiers avec des boutons “Turbo” – dont le but, ironiquement, était de ralentir l’ordinateur afin que les jeux utilisant la technique du retardement puissent être joués à une vitesse raisonnable.


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

Leurs valeurs définies par la mise en œuvre doivent être égales ou supérieures (valeur absolue) à celles indiquées, avec le même signe.

Ainsi, tout nombre égal ou supérieur à 8 convient pour une substitution par une implémentation dans CHAR_BIT .

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

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

J’en connais quelques-uns:

  • DEC PDP-10: variable, mais le plus souvent des caractères de 7 bits avec 5 mots de 36 bits, ou des caractères de 9 bits, 4 par mot
  • Ordinateurs centraux de données de contrôle (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176, etc.) Caractères de 6 bits, 10 par mot de 60 bits.
  • Mainframes Unisys: 9 bits / octet
  • Windows CE: ne supporte tout simplement pas le type `char` – nécessite au lieu de cela 16 bits wchar_t

Il n’existe pas de code complètement 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_BIT et UCHAR_MAX . Oui, il est parfois possible d’écrire du code qui ne dépend pas de la taille du caractère.

Cependant, presque n’importe quel code réel n’est pas autonome. Par exemple, vous écrivez un code qui envoie des messages binarys au réseau (le protocole n’est pas important). Vous pouvez définir des structures contenant des champs nécessaires. Alors vous devez le sérialiser. La copie binary 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. La structure ne contient que les données .

D’accord. Vous pouvez effectuer des transformations d’ordre des octets et déplacer les membres de la structure (par exemple, uint32_t ou similaire) en utilisant memcpy dans le tampon. Pourquoi memcpy ? Parce qu’il y a beaucoup de plates-formes sur lesquelles il n’est pas possible d’écrire 32 bits (16 bits, 64 bits – pas de différence) lorsque l’adresse cible n’est pas correctement alignée.

Vous avez donc déjà fait beaucoup pour atteindre la portabilité.

Et maintenant la dernière question. Nous avons un tampon. Les données sont envoyées au réseau TCP / IP. Ce réseau suppose des octets de 8 bits. La question est: de quel type le tampon devrait ê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 plusieurs octets de réseau sont regroupés dans des caractères 24/16/9 bits? C’est une question et il est difficile de croire qu’il existe une seule réponse 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. Généralement, le code peut être facilement transféré dans une certaine mesure . Il est très important de le faire si vous vous attendez à utiliser le code sur différentes plates-formes. Cependant, l’ amélioration de la portabilité au-delà de cette mesure est une chose qui demande beaucoup d’efforts et donne souvent peu , car le code réel dépend presque toujours d’autres codes (implémentation de socket dans l’exemple ci-dessus). Je suis sûr que pour environ 90% du code, la capacité de travailler sur des plates-formes avec des octets autres que 8 bits est presque inutile, car elle utilise un environnement lié à 8 bits. Vérifiez simplement la taille en octets et effectuez une assertion de compilation. Vous devrez sûrement réécrire beaucoup pour une plateforme très inhabituelle.

Mais si votre code est très “autonome” – pourquoi pas? Vous pouvez l’écrire d’une manière qui permet différentes tailles d’octets.

Il semble que vous puissiez toujours acheter un IM6100 (un PDP-8 sur une puce) hors d’un entrepôt. C’est une architecture 12 bits.

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

Les langages de programmation C et C ++, par exemple, définissent l’octet comme «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). Comme 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 de 8, 9, 16, 32 ou 36 bits

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

Je ne suis pas sûr des autres langues.

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

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

La famille DEC PDP-8 comportait un mot de 12 bits, mais vous utilisiez généralement la norme ASCII 8 bits pour la sortie (sur un télétype principalement). Cependant, il y avait aussi un code de caractère de 6 bits qui vous permettait de coder 2 caractères dans un seul mot de 12 bits.

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. Utilisez sizeof et les valeurs dans limits.h si vous souhaitez interroger vos types de données et découvrir exactement quelle taille ils ont pour votre configuration et votre architecture.

Pour cette raison, j’essaie de coller aux types de données comme uint16_t lorsque j’ai besoin d’un type de données d’une longueur de bit particulière.

Edit: Désolé, j’ai initialement mal interprété votre question.

La spécification C indique qu’un object char est “suffisamment grand pour stocker n’importe quel membre du jeu de caractères d’exécution”. limits.h liste une taille minimale de 8 bits, mais la définition laisse la taille maximale d’un caractère ouvert.

Ainsi, le caractère a est au moins aussi long que le plus grand caractère du jeu d’exécution de votre architecture (généralement arrondi à la limite de 8 bits la plus proche). Si votre architecture a des codes opératoires plus longs, votre taille de caractère peut être plus longue.

Historiquement, l’opcode de la plate-forme x86 avait une longueur d’un octet, de sorte que char était initialement une valeur de 8 bits. Les plates-formes x86 actuelles prennent en charge les opcodes de plus d’un octet, mais le caractère est conservé à une longueur de 8 bits, car c’est ce à quoi les programmeurs (et les gros volumes de code x86 existants) sont conditionnés.

Lorsque vous pensez au support multi-plateforme, tirez parti des types définis dans stdint.h . Si vous utilisez (par exemple) un uint16_t, vous pouvez être sûr que cette valeur est une valeur 16 bits non signée sur n’importe quelle architecture, que cette valeur 16 bits corresponde à un caractère char , short , int ou autre. Le gros du travail a déjà été effectué par les personnes qui ont écrit vos bibliothèques de compilation / standard.

Si vous avez besoin de connaître la taille exacte d’un caractère car 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 caractère sur toutes les plates-formes sockets en charge (généralement 16 bits suffisent) et exécutez la valeur via une routine convert_to_machine_char 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 uint16_t normal.

Quelle sorte de considération vaut-il de donner aux plates-formes avec un caractère non-8-bit?

des nombres magiques apparaissent par exemple lors du changement de vitesse;

la plupart d’entre eux peuvent être manipulés 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 “communs” …..

Un autre problème indirect est que vous avez:

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

cela pourrait “seulement” prendre (le meilleur des cas) 24 bits sur une plate-forme, mais pourrait prendre par exemple 72 bits ailleurs …..

si chaque uchar contenait des “indicateurs de bit” et que chaque uchar ne comportait que 2 bits ou indicateurs “significatifs” que vous utilisiez actuellement, et que vous ne les organisiez que dans 3 uchars pour “clarté”, une plate-forme avec uchars 24 bits …..

rien ne peut résoudre les bitfields, mais ils ont d’autres choses à surveiller…

dans ce cas, un simple chiffre pourrait être un moyen d’obtenir le “plus petit” entier de taille dont vous avez réellement besoin ….

peut-être pas un vrai exemple, mais des trucs comme ça “mord” moi lors du portage / lecture avec du code …..

Juste le fait que si un uchar est trois fois plus gros que ce à quoi on s’attend normalement, 100 de ces structures risquent de gaspiller beaucoup de mémoire sur certaines plates-formes. .

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 “ne gaspille pas beaucoup” sur une plate-forme, par rapport à la RAM disponible, que sur une autre plate-forme … ..

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

“normalement” vous pouvez le diviser en 2 uchars, mais avec un uchar 24 bits par exemple, vous n’en aurez besoin que de …..

donc un enum pourrait être une meilleure solution “générique” ….

dépend de la façon dont vous accédez à ces bits bien 🙂

donc, il pourrait y avoir des “défauts de conception” qui se dressent sur leur tête …. même si le code peut toujours fonctionner correctement indépendamment de 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 🙂

ints était de 16 bits (pdp11, etc.). Passer aux architectures 32 bits était difficile. Les gens vont mieux: à peine, quiconque suppose qu’un pointeur rentre plus longtemps (tu n’as pas raison?). Ou les décalages de fichiers, ou les 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.