-1
votes

Comment puis-je saisir correctement le jeu de mots-mots?

Suivi de la discussion prolongée dans Comment puis-je déterminer si je suis en extensuation?

J'essaie d'émuler un Z80 en C, où plusieurs registres 8 bits peuvent être combinés pour créer des registres 16 bits.

C'est la logique que j'essaie d'utiliser: xxx

Pourquoi est-ce incorrect et comment puis-je le faire correctement (à l'aide de type punning si nécessaire)?

J'ai besoin de faire cela plusieurs fois, de préférence dans la même structure.


1 commentaires

@FidDlingbits parce que je ne savais pas comment utiliser Union s puis. Maintenant, je réalise ce que j'aurais pu faire (bien que ce soit plus facile dans C ++ où je peux utiliser des abstractions au lieu de Union s). Merci pour le conseil.


4 Réponses :


3
votes

Pour émuler un registre matériel pouvant être accessible en deux registres huit bits ou un registre 16 bits, vous pouvez utiliser: xxx

puis regs-> bc sera le registre 16 bits et REGS-> B et REGS-> C sera des registres de 8 bits.

Remarque: Cela utilise un anonyme de sorte que B et c apparaît comme s'il s'agissait de membres de l'Union. Si le struct avait un nom, comme celui-ci: xxx

alors vous devriez inclure son nom lors de l'accès à B ou C , comme avec REGS-> SB . Cependant, C a une fonctionnalité qui vous permet d'utiliser une déclaration sans nom à cette fin.

Notez également que cela nécessite un compilateur C. C permet d'utiliser des syndicats de réinterpréter les données. C ++ a des règles différentes.


2 commentaires

Je me demande si cela peut conduire à des problèmes car b , c et bc sont tous signés.


Je m'attendrais à ce que le Z80 ait une certaine Endian, mais l'Endian de l'environnement d'émulation peut ne pas correspondre. Cela nécessite également une résolution éventuelle par le code de l'OP.



7
votes

Il est incorrect car B code> est de type uint8_t code> et un pointeur sur uint16_t code> ne peut pas être utilisé pour accéder à une telle variable. Il pourrait ne pas être correctement aligné et c'est un violation aliasante stricte .

Vous êtes cependant libre de faire (uint8_t *) & regs code> ou (structure reg_T *) & regs-> B code>, puisque (6.7.2.1/15) P>

Un pointeur sur un objet de structure, converti convenablement, pointe vers son membre initial et vice versa. P> BlockQuote>


Lors de la programmation liée au matériel, assurez-vous de ne jamais utiliser de types signés. Cela signifie changer intn_t code> sur uintn_t code>. P>

Quant à la façon de taper du jeu de mots correctement, utilisez une Union: P>

volatile reg_t* reg = (volatile reg_t*)0x1234;


0 commentaires

3
votes

La bonne voie consiste à traverser des syndicats anonymes en C comme déjà montré dans d'autres réponses. Mais comme vous voulez traiter les octets, vous pouvez utiliser la manipulation spéciale de caractères dans la règle d'aliasing stricte: quel que soit le type, est toujours légal d'utiliser un pointeur de caractère pour accéder aux octets de sa représentation. Donc, c'est conforme C xxx

assez intéressant, il est toujours valide pour un compilateur C ++ ...


3 commentaires

Remarque: non détaillé dans la réponse, mais lorsque uint8_t est défini dans une implémentation C, il doit être non signé char car: 1 / la taille de tout type doit être multiple de La taille de char 2 / la taille de Char est d'au moins 8 bits (5.2.4.2.1 Tailles de types entier ) 3 / la taille de uint8_t est exactement 8 bits.


Vous voulez dire regs-> b = (uint8_t *) & regs-> bc; ouais? Et bien, vous êtes toujours autorisé à convertir énormément des pointeurs. La règle spéciale que vous faites référence est en matière d'itération à travers tout type d'octet-byte-octet et de LValue (6.3.2.3/7).


L'auteur sera certainement conscient, mais que personne n'a dit qu'il est élevé: cela suppose une architecture de petite endienne. Ce qui est une hypothèse très sûre de nos jours, mais pas quelque chose que vous pouvez supposer - donc cela est conforme c mais techniquement ne fonctionnera pas nécessairement comme prévu partout.



-2
votes

Le moyen correct de taper le jeu de mots dans C (ou faites presque n'importe quoi, est d'utiliser une implémentation configurée pour être adaptée à son objectif. La norme permet délibérément les implémentations destinées à diverses fins de se comporter de manière inappropriée à d'autres fins. Selon les auteurs, il n'a jamais été destiné à suggérer que les programmes dont le comportement n'était pas obligatoire par la norme (mais serait défini sur les implémentations pour lesquelles ils étaient destinés) devraient être considérés comme «cassés». Les compilateurs dont les auteurs cherchent à soutenir les besoins de leurs clients reconnaîtront des constructions simples de punning de type simples, que la norme leur oblige à le faire ou non et les optimiseurs que les auteurs souhaitent que les besoins de leurs clients avec mépris ne soient pas confiés à gérer de manière fiable quelque chose de compliqué.


0 commentaires