0
votes

C ++ combinant 2 uint8_t dans un uint16_t ne fonctionne pas?

Donc, j'ai un petit morceau de code qui prend 2 uint8_t et des places alors côte à côte, puis retourne un uint16_t. Le point ne fait pas ajouter les 2 variables, mais les mettre à côté les uns des autres et créer un uint16_t d'eux. La façon dont je m'attends à ce que cela fonctionne, c'est que lorsque le premier uint8_t est 0, et le deuxième uint8_t est 1, je m'attends à ce que l'uint16_t soit aussi un. Cependant, c'est dans mon code pas le cas. Ceci est mon code:

uint8_t *bytes = new uint8_t[2];
bytes[0] = 0;
bytes[1] = 1;
uint16_t out = *((uint16_t*)bytes);


4 commentaires

Vous avez marqué cette question avec "Endianness". Qu'est-ce que vous ne comprenez pas exactement alors? Parce que l'endianness est fondamentalement la réponse.


"Petit Endian" signifie 0xabcd est disposé en tant que 0xcd, 0xab . Êtes-vous confondre les deux types d'endansion?


Ouais je les confondais. Pensait que peu d'endian il s'est terminé par le petit bit.


Ouais je déteste les noms. Je toujours les a mélangés dans mon cerveau pour exactement cette raison. Pourquoi la "fin" signifie que "la première extrémité" est au-delà de moi. Essayez de vous rappeler que Big Endian est la façon dont vous écrivez des numéros dans le système latin (par exemple 12345) (c'est-à-dire pour beaucoup d'entre nous, «normal»), puis travaillez à partir de là


5 Réponses :


2
votes

si p est un pointeur sur une valeur multi-octets, puis:

  • "Little-Endian" signifie que l'octet à P est l'octet , en d'autres termes, il contient des bits 0-7 de la valeur. < / li>
  • "Big-Endian" signifie que l'octet à p est l'octet le plus significatif , qui pour une valeur de 16 bits serait des bits 8-15. < / li>

    Étant donné que l'Intel est petit-Endian, les octets [0] contiennent des bits 0 à 7 de la valeur uint16_t et des octets [1] contient des bits 8-15. Puisque vous essayez de définir un bit 0, vous avez besoin de: xxx


3 commentaires

Merci! Je confondis les endanses. Je pensais que la petite Endian voulait dire que cela s'est terminé par le petit morceau. (Ce qui expliquerait le nom)


L'endiangité affecte-t-elle aussi l'ordre des bits dans l'octet ou non?


@ Sa-A-Me-Mario N °



3
votes

Dans un petit système Endian, les petits octets sont placés en premier. En d'autres termes: le bas d'octet est placé sur un décalage 0 et l'octet élevé sur le décalage 1 (etc.). Donc, ceci: xxx

produit le out = 1 résultat souhaité.

Cependant, comme vous pouvez le constater que c'est facile de se tromper, Donc, en général, je recommanderais que, au lieu d'essayer de placer des trucs correctement en mémoire puis de le jeter, vous faites quelque chose comme ceci: xxx

qui fonctionnera sur n'importe quelle machine, Indépendamment de l'endansnité.

EDIT: ÉDITE DE BITE APPLICATION AJOUTÉE.

X << Y signifie déplacer les bits dans x y des endroits à gauche (>> les déplace vers la droite à la droite).

si X contient le modèle Bit-motif xxxxxxxx et y contient le modèle bit-modèle yyyyyyyy , puis (x << 8) produit le modèle: xxxxxxx00000000 et Y + (x << 8) produit: xxxxxxxxyyyyyyyy .

(et y + (x << 8) + (z << 16) produit zzzzzzzxxxxxxxxxyyyyyyy , etc.)

Un simple passage à gauche est identique à la multiplication par 2, donc x est identique à x * 2 ^ 8 = x * 256 . Cela signifie que vous pouvez également faire: y + (x * 256) + (z * 65536) , mais je pense que les changements sont plus clairs et montrent l'intention mieux.

Note C'est encore une fois: l'endianness n'a pas d'importance. Le changement de 8 bits à gauche effacera toujours les basses bits.

Vous pouvez lire plus ici: https://fr.wikipedia.org/wiki/bitwise_opération . Notez la différence entre les changements arithmétiques et logiques - dans les valeurs non signées C / C ++ utilisent des changements logiques et utilisez des changements arithmétiques.


3 commentaires

@Frodyne pourriez-vous peut-être expliquer comment cela fonctionne? Je ne sais pas encore les opérateurs bitwises.


@ ITS-A-Me-Mario ici Opérateur << () est le décalage vers la gauche vers la gauche. Supposons que vous ayez deux octets, msb == 0x05 et lsb == 0x08 . Ensuite, vous voulez les concaténer dans un uint16_t . Shifting MSB de la taille d'un octet (c'est-à-dire 8) vous donnera 0x0500 ( static_cast résultat à un uint16_t Pour éviter les avertissements de conversion implicites). Ensuite, vous ajoutez le résultat au LSB et vous obtenez 0x0508 quelle concaténation que vous avez désirée.


@ Sa-A-Me-Mario Je viens d'ajouter une brève explication dans une édition. Mais fondamentalement, ce que Faréanor a dit.



4
votes

Il n'y a pas de uint16_t code> ou objet compatible à cette adresse, et donc le comportement de * ((uint16_t *) octets) code> est indéfini.

Je m'attends à ce que la valeur soit 1 puisque x86 est petite Endian. Cependant, il retourne 256. P> BlockQuote>

Même si le programme était fixé pour avoir un comportement bien défini, votre attente est à l'envers. Dans la petite Endian, l'octet le moins important est stocké dans l'adresse la plus basse. Ainsi, 2 octets la valeur 1 est stockée comme 1, 0 et pas 0, 1. P>

L'endianesse affecte également l'ordre du bit dans l'octet ou non? p> blockQuote>

Il n'y a aucun moyen d'accéder à un peu par "adresse" 1 sup>, donc il n'y a pas de concept d'endansité. Lors de la conversion en texte, les bits sont classiquement montrés le plus important à gauche et le moins à droite; comme des chiffres de nombres décimaux. Je ne sais pas si cela est vrai dans les systèmes d'écriture droite à gauche. P>

1 sup> Vous pouvez trier des "adresses virtuelles" pour les bits à l'aide de bitfields. L'ordre des champs de bit, c'est-à-dire si le premier bitfield est le plus ou le moins significatif est la mise en œuvre définie et non nécessairement liée à l'endansité des octets. P>


Voici un moyen correct de définir deux octets comme uint16_t code>. Le résultat dépendra de l'endianness du système: p>

// no need to complicate a simple example with dynamic allocation
uint16_t out;
// note that there is an exception in language rules that
// allows accessing any object through narrow (unsigned) char
// or std::byte pointers; thus following is well defined
std::byte* data = reinterpret_cast<std::byte*>(&out);
data[0] = 1;
data[1] = 0;


11 commentaires

En effet, un std :: copier (ou équivalent) est requis pour un comportement bien défini ici.


Eh bien, ou commencez avec un uint16_t puis écrivez via un uint8_t * dans. Puis imprimer le bâtard


Int est juste un ensemble de bits. Donc, je ne pense pas que C ++ puisse dire la différence, non?


@ Sa-A-Me-Mario Ce n'est pas comme ça que ça marche. Je vous suggère de lire sur aliasing strict : Stackoverflow.com/questions/98650/...


@Lightnessrsinorbit Pourquoi ce que j'ai fait un comportement indéfini? Je ne comprends pas vraiment.


@ Sa-A-Me-Mario parce qu'il enfreint un aliasage strict. La première phrase de cette réponse est la raison précise de la norme C ++, ainsi que votre programme a un comportement indéfini. Vous semblez penser que vous ne pouvez avoir que UB si "quelque chose de mauvais" se produit en raison de votre violation de la norme, mais ce n'est pas ce que l'UB est. En fait, cela peut fonctionner correctement sur votre compilateur, mais il n'existe aucune garantie de ce type de la norme C ++ et il peut se casser à tout moment, car l'UB signifie "Vous violez une hypothèse que les écrivains compilateurs sont garantis par la norme".


@Maxlanghof j'ai lu le lien, mais ne l'obtenez pas vraiment. Un aliasing strict s'applique-t-il uniquement lors de la coulée à un type différent de différentes tailles, ou pour tout ce qui n'est pas une classe qui n'est pas doyrée de quelque chose?


@ Sa-A-Me-Mario Il s'applique chaque fois que vous mentez au compilateur sur quel objet vous attendez de trouver quelque part par rapport à quel objet est vraiment. Si vous avez créé deux uint16_t S adjacent en mémoire, puis accédez à cet emplacement via un uint32_t * , qui enfreint un aliasage strict parce que no uint32_t L'objet existe à cet emplacement de la mémoire . Du point de vue de la norme, chaque entier (et tout le reste) que vous écrivez à la mémoire est un objet, pas seulement une masse aléatoire de bits / octets, et il accorde des compilateurs le droit de supposer que vous ne écrasez pas la moitié de l'objet avec quelque chose.


@ Sa-ME-Me-Mario Il s'applique à l'accès à tout point de pointe (ou référence) réinterpret de manière à un type différent, quelle que soit leur taille, que ce soit une classe ou non. Il existe des exceptions telles que t peut être réinterprété comme const t et tout peut être réinterprété via char le pointeur et les objets de classe standard peuvent être réinterprétés comme leur premier objet membre


"int's est juste un ensemble de morceaux. Donc, je ne pense pas que c ++ peut dire la différence, non?" Cette déclaration est fausse, et c'est pourquoi vous avez UB et pourquoi cela compte. Les objets ne sont pas simplement une charge de bits. Vous n'êtes pas la programmation de la main d'un ordinateur physique. C ++ est une abstraction et les compilateurs / optimiseurs sont incroyablement, incroyablement, incroyablement compliqué. Ils prendront toutes les occasions possibles pour faire des raccourcis, et cela le fera de manière à la coupe qui se casse lorsque vous violez le contrat. Ici vous prétendez un uint16_t existe quand, académiquement, ce n'est pas le cas. Et cela compte pour le compilateur.


C'est une idée fausse commune, alors ne vous sentez pas mal. Beaucoup de personnes écrivant C ++ prennent toujours une sorte d'approche de la programmation des années 1970 en 1970 (ce n'est que quelques octets en mémoire, non?), Mais la réalité est complètement différente. Rappelez-vous simplement que Vous décrivez le comportement d'un programme (ne programmant pas réellement les puces de mémoire d'un ordinateur), puis tout ira bien.



1
votes

Votre code fonctionne mais votre mal interprété comment lire "octets" xxx

d'ailleurs, vous devez prendre soin de alignement lors de la coulée de cette façon.


0 commentaires

0
votes

Une façon de penser en chiffres consiste à utiliser le MSB et la commande LSB
qui est MSB est le bit le plus élevé et le LSB est le plus bas le plus bas pour
Petites machines Endian.

pour ex. xxx


0 commentaires