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. P>
C'est la logique que j'essaie d'utiliser: p> Pourquoi est-ce incorrect et comment puis-je le faire correctement (à l'aide de type punning si nécessaire)? P> J'ai besoin de faire cela plusieurs fois, de préférence dans la même structure. p> p>
4 Réponses :
Pour émuler un registre matériel pouvant être accessible en deux registres huit bits ou un registre 16 bits, vous pouvez utiliser: puis Remarque: Cela utilise un alors vous devriez inclure son nom lors de l'accès à 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. P> p> regs-> bc Code> sera le registre 16 bits et
REGS-> B code> et
REGS-> C code> sera des registres de 8 bits. P>
anonyme code> de sorte que
B code> et
c code> apparaît comme s'il s'agissait de membres de l'Union. Si le
struct code> avait un nom, comme celui-ci: p>
B code> ou
C code>, comme avec
REGS-> SB code>. Cependant, C a une fonctionnalité qui vous permet d'utiliser une déclaration sans nom à cette fin. P>
Je me demande si cela peut conduire à des problèmes car b code>,
c code> et
bc code> 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.
Il est incorrect car Vous êtes cependant libre de faire 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 Quant à la façon de taper du jeu de mots correctement, utilisez une Union: P> 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 .
(uint8_t *) & regs code> ou
(structure reg_T *) & regs-> B code>, puisque (6.7.2.1/15) P>
intn_t code> sur
uintn_t code>. P>
volatile reg_t* reg = (volatile reg_t*)0x1234;
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 assez intéressant, il est toujours valide pour un compilateur C ++ ... p> p>
Remarque: non détaillé dans la réponse, mais lorsque uint8_t code> est défini dans une implémentation C, il doit être
non signé char code> car: 1 / la taille de tout type doit être multiple de La taille de
char code> 2 / la taille de
Char code> est d'au moins 8 bits (5.2.4.2.1 Tailles de types entier
uint8_t code> est exactement 8 bits.
Vous voulez dire regs-> b = (uint8_t *) & regs-> bc; code> 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.
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é. p>
@FidDlingbits parce que je ne savais pas comment utiliser
Union code> 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 code> s). Merci pour le conseil.