Quelle est la nature des littéraux binarys en C ++ 14?

J’ai essayé de chercher autour de moi mais je n’ai pas pu trouver beaucoup de choses sur les littéraux binarys et l’endianness. Les littéraux binarys sont-ils peu endian, big-endian ou autre chose (par exemple, correspondre à la plate-forme cible)?

Par exemple, quelle est la valeur décimale de 0b0111 ? Est-ce que c’est 7? Plateforme spécifique? Autre chose? Edit: J’ai choisi une mauvaise valeur de 7 car elle est représentée dans un octet. La question a reçu une réponse suffisante malgré ce fait.

Quelques fondements: En gros, j’essaie de déterminer la valeur des bits les moins significatifs et de la masquer avec des littéraux binarys semble être un bon moyen d’y parvenir … mais seulement s’il ya une certaine garantie d’endianness.

Réponse courte: il n’y en a pas .

Réponse longue: L’endianness n’est jamais exposé directement dans le code, sauf si vous essayez vraiment de le sortir (par exemple, en utilisant des astuces de pointeur). 0b0111 est 7, ce sont les mêmes règles que l’hexagone, l’écriture

 int i = 0xAA77; 

ne signifie pas 0x77AA sur certaines plates-formes car cela serait absurde. Où les 0 supplémentaires qui manquent vont-ils quand même avec des ints de 32 bits? Seraient-ils rembourrés sur le devant, puis le tout retourné à 0x77AA0000 , ou seraient-ils ajoutés après? Je n’ai aucune idée de ce que quelqu’un pourrait attendre si tel était le cas.

Le fait est que C ++ ne fait aucune hypothèse sur la nature de la machine, si vous écrivez du code en utilisant les primitives et les littéraux qu’il fournit, le comportement sera le même d’une machine à l’autre vous devrez peut-être faire)

Pour répondre à votre mise à jour: le numéro sera la manière dont vous l’écrivez. Les bits ne seront pas réorganisés ou rien de tel, le bit le plus significatif est à gauche et le bit le moins significatif à droite.


Il semble y avoir un malentendu à propos de ce qu’est l’endianness . Endianness fait référence à la manière dont les octets sont classés en mémoire et comment ils doivent être interprétés. Si je vous ai donné le chiffre “4172” et que vous avez dit “si cela fait quatre mille cent soixante-deux, quelle est la nature de la lettre”, vous ne pouvez pas vraiment répondre car la question n’a pas de sens. ( certains prétendent que le plus grand chiffre de gauche signifie big endian, mais sans la mémoire, la question de l’endianness n’est pas responsable ou pertinente ). Ceci est juste un nombre, il n’y a pas d’octets à interpréter, il n’y a pas d’adresses mémoire. En supposant une représentation entière de 4 octets, les octets qui lui correspondent sont:

  low address ----> high address Big endian: 00 00 10 4c Little endian: 4c 10 00 00 

Donc, étant donné l’un ou l’autre de ceux-ci et dit “c’est la représentation interne de l’ordinateur de 4172”, vous pouvez déterminer si c’est le petit ou le grand endian.

Considérons maintenant votre littéral binary 0b0111 ces 4 bits représentent un nybble, et peuvent être stockés soit

  low ---> high Big endian: 00 00 00 07 Little endian: 07 00 00 00 

Mais vous n’avez pas à vous soucier car cela est également géré par le matériel, le langage dicte que le compilateur lit de gauche à droite, le bit le plus significatif au bit le moins significatif

L’endianness ne concerne pas les bits individuels . Étant donné qu’un octet est de 8 bits, si je vous 0b00000111 et que vous dites “est-ce que c’est un petit ou un gros boutiste?” encore une fois vous ne pouvez pas dire parce que vous avez seulement un octet. Endianness ne réorganise pas les bits dans un octet, se réfère à la réorganisation des octets entiers (à moins bien sûr que vous ayez des octets d’un bit).

Vous n’avez pas à vous soucier de ce que votre ordinateur utilise en interne. 0b0111 vous fait gagner du temps en écrivant des choses comme

 unsigned int mask = 7 // only keep the lowest 3 bits 

en écrivant

 unsigned int mask = 0b0111; 

Sans avoir besoin de commenter en expliquant la signification du numéro.

Tous les littéraux entiers, y compris ceux qui sont binarys, sont interprétés de la même manière que nous lisons normalement les nombres (les chiffres les plus à gauche sont les plus significatifs).

Le standard C ++ garantit la même interprétation des littéraux sans avoir à se soucier de l’environnement spécifique sur lequel vous vous trouvez. Ainsi, vous n’avez pas à vous soucier de l’endianisme dans ce contexte.

Votre exemple de 0b0111 est toujours égal à sept.

Le standard C ++ n’utilise pas de termes d’endianness en ce qui concerne les littéraux numériques. Au contraire, cela décrit simplement que les littéraux ont une interprétation cohérente et que l’interprétation est celle à laquelle vous vous attendez.

C ++ Standard – Integer Literals – 2.14.2 – paragraphe 1

Un littéral entier est une séquence de chiffres sans partie de période ni d’exposant, avec des guillemets simples de séparation facultatifs qui sont ignorés lors de la détermination de sa valeur. Un littéral entier peut avoir un préfixe qui spécifie sa base et un suffixe qui spécifie son type. Le premier chiffre lexical de la séquence de chiffres est le plus significatif. Un entier binary littéral (base deux) commence par 0b ou 0B et consiste en une séquence de chiffres binarys. Un entier littéral octal (base huit) commence par le chiffre 0 et consiste en une séquence de chiffres octaux. Un entier décimal littéral (base dix) commence par un chiffre autre que 0 et consiste en une séquence de chiffres décimaux. Un entier hexadécimal littéral (base seize) commence par 0x ou 0X et consiste en une séquence de chiffres hexadécimaux, qui inclut les chiffres décimaux et les lettres a à f et A à F avec des valeurs décimales de dix à quinze. [Exemple: le nombre douze peut être écrit 12, 014, 0XC ou 0b1100. Les littéraux 1048576, 1’048’576, 0X100000, 0x10’0000 et 0’004’000’000 ont tous la même valeur. – exemple de fin]

Wikipedia décrit ce qu’est l’endianness et utilise notre système de numérotation comme exemple pour comprendre le big-endian .

Les termes endian et endianness font référence à la convention utilisée pour interpréter les octets constituant un mot de données lorsque ces octets sont stockés dans la mémoire de l’ordinateur.

Les systèmes Big-endian stockent l’octet le plus significatif d’un mot dans la plus petite adresse et l’octet le moins significatif est stocké dans la plus grande adresse (voir également Bit le plus significatif). Les systèmes Little-endian, en revanche, stockent l’octet le moins significatif dans la plus petite adresse.

Un exemple de l’endianness est de penser à la manière dont un nombre décimal est écrit et lu dans la notation de la valeur de position. En supposant un système d’écriture où les nombres sont écrits de gauche à droite, la position la plus à gauche est analogue à la plus petite adresse de mémoire utilisée et la position la plus à droite est la plus grande. Par exemple, le nombre cent vingt trois est écrit 1 2 3, avec les centaines à gauche. Quiconque lit ce numéro sait également que le chiffre le plus à gauche est celui qui a la plus grande valeur. C’est un exemple d’une convention big-endian suivie dans la vie quotidienne.

Dans ce contexte, nous considérons qu’un chiffre d’un entier littéral est un “octet d’un mot”, et le mot est le littéral lui-même. En outre, le caractère le plus à gauche dans un littéral est considéré comme ayant la plus petite adresse.

Avec le littéral 1234 , les chiffres un, deux, trois et quatre sont les “octets d’un mot” et 1234 est le “mot”. Avec le littéral binary 0b0111 , les chiffres zéro, un, un et un sont les “octets d’un mot” et le mot est 0111 .

Cette considération nous permet de comprendre l’endianness dans le contexte du langage C ++ et montre que les littéraux entiers sont similaires au “big-endian”.

Vous manquez la distinction entre endianness comme écrit dans le code source et endianness comme représenté dans le code object. La réponse à chacun est sans surprise: les littéraux de code source sont bigendiens car c’est comme ça que les humains les lisent, dans le code object ils sont écrits mais la cible les lit.

Comme un octet est par définition la plus petite unité d’access à la mémoire, je ne pense pas qu’il serait possible d’atsortingbuer même un endian à une représentation interne de bits dans un octet – la seule façon de découvrir l’endianité pour des nombres plus importants par surprise) consiste à y accéder depuis le stockage par morceaux, et l’octet est par définition la plus petite unité de stockage accessible.

Les langages C / C ++ ne se soucient pas de l’endianité des entiers multi-octets. Les compilateurs C / C ++ le font. Les compilateurs parsingnt votre code source et génèrent du code machine pour la plate-forme cible spécifique. Le compilateur, en général, stocke les littéraux entiers de la même manière qu’il stocke un entier; de telle sorte que les instructions du processeur cible prennent directement en charge leur lecture et leur écriture en mémoire.

Le compilateur prend en charge les différences entre les plates-formes cibles pour que vous n’ayez pas à le faire.

La seule fois où vous devez vous soucier de l’endianisme, c’est lorsque vous partagez des valeurs binarys avec d’autres systèmes qui ont un ordre d’octets différent. Vous pouvez alors lire les données binarys, octet par octet et organiser les octets dans le bon ordre pour le système sur lequel votre code est exécuté.

Une image est parfois plus de mille mots.

source vs mémoire endianness

L’endianness est défini par la mise en œuvre. La norme garantit que chaque object possède une représentation d’object sous la forme d’un tableau de caractères char et unsigned char , avec lequel vous pouvez travailler en appelant memcpy() ou memcmp() . En C ++ 17, il est légal de reinterpret_cast un pointeur ou une référence à un type d’object (pas un pointeur sur void , un pointeur sur une fonction ou nullptr ) vers un pointeur sur char , unsigned char ou std::byte , qui sont des alias valides pour tout type d’object.

Ce que les gens veulent dire par «endianness», c’est l’ordre des octets dans cette représentation d’object. Par exemple, si vous déclarez unsigned char int_bytes[sizeof(int)] = {1}; et int i; puis memcpy( &i, int_bytes, sizeof(i)); obtenez-vous 0x01, 0x01000000, 0x0100, 0x0100000000000000 ou autre chose? La réponse est oui. Il existe des implémentations réelles qui produisent chacun de ces résultats, et elles sont toutes conformes à la norme. La raison en est que le compilateur peut utiliser le format natif du processeur.

Cela se produit le plus souvent lorsqu’un programme doit envoyer ou recevoir des données via Internet, où tous les standards définissent que les données doivent être transmises dans l’ordre big-endian, sur un processeur peu endian comme le x86. Certaines bibliothèques réseau spécifient donc si des arguments et des champs de structures particuliers doivent être stockés dans l’ordre des octets de l’hôte ou du réseau.

Le langage vous permet de vous photographier dans le pied en tortillant arbitrairement les bits d’une représentation d’object, mais cela pourrait vous donner une représentation de piège , qui pourrait entraîner un comportement indéfini si vous essayez de l’utiliser plus tard. (Cela peut vouloir dire, par exemple, réécrire une table de fonction virtuelle pour injecter du code arbitraire.) L’en-tête a plusieurs modèles pour tester s’il est sécuritaire de faire des choses avec une représentation d’object. Vous pouvez copier un object sur un autre du même type avec memcpy( &dest, &src, sizeof(dest) ) si ce type is_sortingvially_copyable . Vous pouvez effectuer une copie dans la mémoire non initialisée correctement alignée si elle is_sortingvially_move_constructible . Vous pouvez tester si deux objects du même type sont identiques à memcmp( &a, &b, sizeof(a) ) et memcmp( &a, &b, sizeof(a) ) correctement un object en appliquant une fonction de hachage aux octets dans sa représentation d’object si le type has_unique_object_representations . Un type intégral ne comporte aucune représentation d’interruption, etc. Pour la plupart, cependant, si vous effectuez des opérations sur des représentations d’objects où la finalité est importante, vous dites au compilateur de supposer que vous savez ce que vous faites et que votre code ne sera pas portable.

Comme d’autres l’ont mentionné, les littéraux binarys sont écrits avec les caractères les plus significatifs en premier, comme les littéraux décimaux, octaux ou hexadécimaux. Ceci est différent de l’endianness et n’affectera pas si vous devez appeler ntohs() sur le numéro de port à partir d’un en-tête TCP lu depuis Internet.

En plus, je dirai que même le compilateur ne se soucie pas, par exemple dans la plate-forme LLVM, seul le backend (techniquement pas un compilateur) se chargera de l’endianess.

Vous voudrez peut-être penser à C ou C ++ ou à tout autre langage comme étant insortingnsèquement peu endian (pensez au fonctionnement des opérateurs binarys). Si le HW sous-jacent est big endian, le compilateur garantit que les données sont stockées dans big endian (idem pour les autres endianness), mais vos opérations sur les bits fonctionnent comme si les données étaient peu endian. Ce qu’il faut retenir, c’est que pour ce qui concerne la langue, les données sont en petit format. Les problèmes liés à l’endianisme surviennent lorsque vous convertissez les données d’un type à l’autre. Tant que tu ne le fais pas, tu es bon.

J’ai été interrogé sur la déclaration “le langage C / C ++ comme étant insortingnsèquement peu endian”, en tant que tel, je fournis un exemple que beaucoup connaissent comment cela fonctionne, mais bon ici je vais.

 typedef union { struct { int a:1; int reserved:31; } bits; unsigned int value; } u; u test; test.bits.a = 1; test.bits.reserved = 0; printf("After bits assignment, test.value = 0x%08X\n", test.value); test.value = 0x00000001; printf("After value assignment, test.value = 0x%08X\n", test.value); 

Sortie sur un petit système endian:

 After bits assignment, test.value = 0x00000001 After value assignment, test.value = 0x00000001 

Sortie sur un système big endian:

 After bits assignment, test.value = 0x80000000 After value assignment, test.value = 0x00000001 

Donc, si vous ne connaissez pas la nature du processeur , où tout sort-il correctement? dans le petit système endian! Ainsi, je dis que le langage C / C ++ est insortingnsèquement peu endian.