Qu'est-ce que l'endianité des littérales binaires en C++14?
j'ai essayé de chercher autour mais n'ai pas été en mesure de trouver beaucoup sur les littérales binaires et l'endianess. Les littérales binaires sont-elles little-endian, big-endian ou autre chose (comme l'appariement de la plate-forme cible)?
a titre d'exemple, Quelle est la valeur décimale de 0b0111
? Il est 7 heures? Plate-forme spécifique? Quelque chose d'autre? Edit: j'ai choisi une mauvaise valeur de 7 puisqu'il est représenté à l'intérieur d'un octet. Malgré cela, la réponse à cette question est suffisante. fait.
un peu d'arrière-plan: fondamentalement, j'essaie de comprendre ce que la valeur des bits les moins significatifs sont, et le masquer avec des littérales binaires semble une bonne façon de procéder... mais seulement s'il y a une garantie sur l'ennui.
8 réponses
brève réponse:il n'y en a pas.
longue réponse:
Endianness n'est jamais exposé directement dans le code à moins que vous essayiez vraiment de le sortir (comme utiliser des trucs de pointeur). 0b0111
7, c'est les mêmes règles que hex, écrit
int i = 0xAA77;
ne signifie pas 0x77AA
sur certaines plateformes parce que ce serait absurde. Où iraient les 0 qui manqueraient de toute façon avec des ints de 32 bits? Seraient-ils obtenir rembourré à l'avant, puis le tout retourné 0x77AA0000
, ou seraient-ils ajoutés après? Je n'ai aucune idée de ce que quelqu'un attendrait si c'était le cas.
Le point est que le C++ n'est pas de faire des hypothèses sur le boutisme de la machine, si vous écrivez du code à l'aide de primitives et les littéraux il fournit, le comportement sera le même de machine à machine (sauf si vous commencez à contourner le système de type, vous pouvez avoir besoin de le faire)
pour répondre À votre mise à jour: le nombre sera la façon dont vous l'écrire. Les bits ne seront pas réordonnés ou n'importe quelle chose du genre, le bit le plus significatif est sur la gauche et le bit le moins significatif est sur la droite.
il semble y avoir un malentendu ici sur ce qu'est l'ennui. L'ennui se rapporte à la façon dont octets sont ordonnées en mémoire et comment elles doivent être interprétées. Si je vous donnais le numéro "4172" et que je disais: "Si c'est quatre mille cent soixante-douze, Quelle est l'énigme" tu ne peux pas vraiment répondre parce que la question n'a pas de sens. ( certains soutiennent que le plus grand chiffre sur la gauche signifie grand endian, mais sans mémoire aborde la question de l'endianité n'est pas répondable ou pertinent). C'est juste un nombre, il n'y a pas d'octets à interpréter, il n'y a pas des adresses de 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, de ceux et me dit "c'est la la représentation interne de l'ordinateur de 4172" vous pourriez déterminer si son petit ou grand endian.
alors maintenant considérez votre binaire littéral0b0111
ces 4 bits représentent un nybble, et peuvent être stockés comme
low ---> high
Big endian: 00 00 00 07
Little endian: 07 00 00 00
mais vous n'avez pas à vous en soucier parce que cela est également géré par le matériel, le langage dicte que le compilateur lit de gauche à droite, bit le plus significatif à bit le moins significatif
L'ennui ne concerne pas l'individu bits. Étant donné qu'un octet est de 8 bits, si je vous donne 0b00000111
et dire "est-ce que c'est petit ou gros endian?"encore une fois, tu ne peux pas le dire car tu n'as qu'un octet. Endianness ne réordonne pas les bits dans un octet, se réfère à la réordination des Octets entiers (à moins bien sûr que vous ayez des octets d'un bit).
Vous n'avez pas à se soucier de ce que votre ordinateur utilise en interne. 0b0111
vous économise juste le temps d'avoir à écrire des choses comme
unsigned int mask = 7 // only keep the lowest 3 bits
par écrit
unsigned int mask = 0b0111;
sans avoir à commenter la signification du nombre.
toutes les lettres entières, y compris les lettres binaires, sont interprétées de la même manière que nous lisons normalement les nombres (la plupart des chiffres à gauche étant les plus significatifs).
la norme c++ garantit la même interprétation des littérales sans avoir à se préoccuper de l'environnement spécifique dans lequel vous évoluez. Donc, vous n'avez pas à vous préoccuper de l'endianness dans ce contexte.
votre exemple de 0b0111
est toujours égale à sept.
la norme c++ n'utilise pas de termes d'endianess en ce qui concerne les littérales numériques. Plutôt, il décrit simplement que les littéraux ont une interprétation cohérente, et que l'interprétation est celui que vous attendez.
C++ Standard - les Littéraux Entiers - 2.14.2 - paragraphe 1
Un entier littéral est une séquence de chiffres qui n'a pas de période ou partie exposant, avec possibilité de séparer les guillemets simples 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 lexicalement le premier chiffre de la séquence des chiffres est le plus significatif. Un binaire entier littéral (base deux) commence par 0b ou 0B et se compose de une séquence de chiffres binaires. un entier octal littéral (base huit) commence par le chiffre 0 et consiste en une séquence de octale. Un nombre entier décimal littéral (base dix) commence avec un chiffre autre que 0 et se compose d'une séquence de chiffres décimaux. Un entier hexadécimal littéral (base seize) commence par 0x ou 0X et se compose d'une séquence de chiffres hexadécimaux, qui comprennent les chiffres décimaux et les lettres a à f et A à F avec des valeurs décimales dix à quinze. [Exemple: le nombre douze peut être écrit 12, 014, 0XC, ou 0b1100. Les littéraux de 1048576, 1’048’576, 0X100000, 0x10’0000,, et 0’004’000’000 ont tous la même valeur. fin de l'exemple ]
Les termes endian et endianness se référer à la convention utilisée pour interpréter les octets qui composent un mot de données lorsque ces octets sont stockés dans la mémoire de l'ordinateur.
les systèmes big-endian stockent le octet le plus significatif d'un mot dans le la plus petite adresse et la plus petite octet significatif est stocké dans le la plus grande adresse (voir aussi bit le plus significatif). Little-endian les systèmes, en revanche, stockent le moindre octet significatif dans le plus petit adresse.
Un exemple sur l'endianness est de penser à la façon dont un nombre décimal ecrit et lu en place-notation de la valeur. 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 le plus la position de la les plus grands. Par exemple, le nombre cent vingt-trois est écrit 1 2 3, avec les centaines de place le plus à gauche. toute personne qui lit ce nombre sait aussi que le chiffre le plus à gauche a la plus grande place valeur. Il s'agit d'un exemple de convention big-endian vie.
Dans ce contexte, nous envisageons un chiffres d'un entier littéral d'être un "octet d'un mot", et le mot à la lettre elle-même. Aussi, le personnage le plus à gauche dans un littérale 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 la "parole". Avec le binaire littéral 0b0111
, les chiffres de 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'endianité dans le contexte du langage C++, et montre que la littérature entière est similaire à "big-endian".
vous ne faites pas la distinction entre l'endianité telle qu'elle est écrite dans le code source et l'endianité telle qu'elle est représentée dans le code objet. La réponse pour chacun n'est pas surprenante: les littérales source-code sont bigendiennes parce que c'est comme ça que les humains les lisent, en code objet elles sont écrites cependant la cible les lit.
Puisqu'un octet est par définition la plus petite unité d'accès à la mémoire, Je ne crois pas qu'il soit possible d'attribuer une quelconque endianité à une représentation interne de bits dans un octet -- la seule façon de découvrir l'endianness pour les plus grands nombres (intentionnellement ou par surprise) est d'y accéder par morceaux de stockage, et le 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. Compilateurs C/C++ n'. Les compilateurs analysent 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 entiers littéraux de la même manière qu'il stocke un entier; de sorte que les instructions du CPU cible supporteront directement la lecture et l'écriture en mémoire.
le compilateur prend en charge les différences entre les plates-formes cibles de sorte que vous n'avez pas de.
la seule fois où vous avez besoin de vous inquiéter de l'Enness, c'est lorsque vous partagez des valeurs binaires avec d'autres systèmes qui ont un ordre d'octet différent.Alors que vous lisez les données binaires, octet par octet, et d'organiser les octets en mémoire dans l'ordre correct pour le système que votre code s'exécute.
Endianness la mise en œuvre est définie. La norme garantit que chaque objet a une représentation d'objet comme un tableau de 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 à n'importe quel type d'objet (pas un pointeur vers void
, pointeur à une fonction, ou nullptr
) à un pointeur sur char
,unsigned char
, ou std::byte
, qui sont des alias valide pour n'importe quel type d'objet.
ce que les gens pensent quand ils parler de "boutisme" est l'ordre des octets dans l'objet de la représentation. Par exemple, si vous déclarez unsigned char int_bytes[sizeof(int)] = {1};
et int i;
memcpy( &i, int_bytes, sizeof(i));
obtenez-vous 0x01, 0x01000000, 0x0100, 0x0100000000000000, ou quelque chose d'autre? La réponse est: oui. Il y a 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 CPU.
cela se produit le plus souvent quand un programme a besoin pour envoyer ou recevoir des données sur Internet, où toutes les normes définissent que les données doivent être transmises dans l'ordre big-endian, sur un processeur little-endian comme le x86. Certaines bibliothèques réseau spécifient donc si des arguments particuliers et des champs de structures doivent être stockés dans l'ordre host ou network byte.
le langage vous permet de vous tirer dans le pied en tournant arbitrairement les bits d'une représentation d'objet, mais il pourrait vous obtenir un piège représentation, qui pourrait causer un comportement non défini si vous essayez de l'utiliser plus tard. (Cela pourrait signifier, par exemple, réécrire une table de fonction virtuelle pour injecter du code arbitraire.)<type_traits>
en-tête a plusieurs gabarits pour tester s'il est sûr de faire des choses avec une représentation d'objet. Vous pouvez copier un objet sur un autre du même type avec memcpy( &dest, &src, sizeof(dest) )
si ce type is_trivially_copyable
. Vous pouvez faire une copie à une mémoire non initialisée alignée correctement si elle is_trivially_move_constructible
. Vous pouvez tester si deux les objets du même type sont identiques avec memcmp( &a, &b, sizeof(a) )
et hachez correctement un objet en appliquant une fonction de hachage aux octets dans sa représentation d'objet si le type has_unique_object_representations
. Un type intégral n'a pas de représentations de piège, et ainsi de suite. Pour la plupart, cependant, si vous effectuez des opérations sur des représentations d'objets où l'ennui est important, 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é, binaire les littérales sont écrites avec le premier chiffre le plus significatif, comme les littérales décimales, octales ou hexidécimales. Ceci est différent de l'endianness et n'affectera pas si vous avez besoin d'appeler ntohs()
sur le numéro de port d'un en-tête TCP lu depuis L'Internet.
en plus, je dirai même compilateur prendre aucun soin, par exemple dans LLVM plate-forme uniquement le backend (techniquement pas un compilateur) prendra soin d'endianess.
vous pourriez vouloir penser à C ou C++ ou tout autre langage comme étant intrinsèquement petit endian (pensez à la façon dont les opérateurs bitwise fonctionnent). Si le HW sous-jacent est big endian, le compilateur s'assure que les données sont stockées en big endian (iditto pour autre endianness) cependant vos opérations de bit wise fonctionnent comme si les données étaient little endian. Ce qu'il faut se rappeler, c'est qu'en ce qui concerne la langue, les données sont en petit-indien. Des problèmes liés à l'Endianness se posent lorsque vous moulez les données à partir type de l'un à l'autre. Tant que vous ne faites pas que vous êtes bon.
on m'a interrogé sur l'énoncé "C / C++ language as being intrinsically little endian", en tant que tel je fournis un exemple que beaucoup savent comment cela fonctionne mais bien voilà.
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 grand système endian:
After bits assignment, test.value = 0x80000000
After value assignment, test.value = 0x00000001
Donc, si vous ne connaissez pas l'endianness du processeur, d'où vient tout sortir à droite? dans le petit système endian! Ainsi, je dis que le langage C/c++ est intrinsèquement peu endian.