8
votes

GCC - struct définissant des membres dans des compensations spécifiques

Y a-t-il un moyen de définir une manière dans GCC, où je pourrais définir une structure avec un élément spécifique dans un décalage spécifique?

Je veux définir une structure de la manière suivante: P>

struct __attribute__ ((__packed__)) struct {
   char pad1[0xD8];
   int bar;
   char pad2[0x18];
   int moo;
}foo;


2 commentaires

Vouliez-vous dire champs de bit ?


Je pense que non, et si vous voulez vraiment des compensations constantes, je le ferai avec des moulages et des pointeurs, comme par exemple. * ((int *) (((char *) p) + 0xd8)) que vous pourriez cacher dans une macro.


7 Réponses :


2
votes

Vous pouvez toujours le rembourrer avec des octets et vous assurer que vous dites à GCC de ne pas aligner vos structures (car cela pourrait jeter les décalages). Dans ce cas, vous auriez besoin d'un membre comme char pad_bytes [num_pad_bytes]; . Bien qu'il y ait une raison de vraiment faire cela? Vous pouvez toujours calculer le décalage d'un membre d'une structure en faisant du pointeur arithmétique. Remarque: Vous voudrez peut-être utiliser le type UINT8_T au tampon au lieu de charme, car certains compilateurs peuvent réellement couvrir le char (qui est généralement un octet) à la taille d'un mot.

Calculer le décalage est comme simple comme xxx

tout cela est simplement renvoyer un pointeur sur l'endroit où le membre serait dans Struct_Type si la structure était à 0x00 en mémoire (qu'elle ne peut jamais être), mais depuis que nous Utilisez 0 comme base, le décalage est simplement la référence renvoyée par le & opérateur.


12 commentaires

" Tout cela fait est simplement " obtenir un comportement indéfini. Vous êtes la déséroférance d'un pointeur NULL!


@Curiousguy Nope en fait, cela ne la dérange pas en fait à cause de l'opérateur. La mise en oeuvre générique de la liste liée à C utilise cette macro exacte (dans le noyau Linux aussi bien rechercher le conteneur_of macro). Voici le lien pour vous juste au cas où LXR.Linux .no / # Linux + v3.1.2 / Inclure / Linux / STDDEF.H # L20


@Jesusramos, dans ce cas, vous devez utiliser le code de macro compensé de C99 / C ++ 98 / C ++ parfaitement standard.


" char (qui est généralement un octet) " a char par définition est un octet, il n'entre donc aucun alignement (alignement = 1).


" Vous pouvez supprimer votre bowvote maintenant :) " Je ne peux pas. Une déréférence est une déréférence et UB est UB. * p est une déréférence de p , et il est illégal si p ne pointe pas sur un objet .


@CuciousGuy Il n'est pas illégal, et est une adresse de l'opérateur, vous n'utilisez pas réellement la valeur pointée là-bas ou même la désarférence du tout. Le caractère également est parfois aligné sur une taille de mot (4 octets ou plus), ce que je voulais dire que tout décalage qui n'est pas aligné sur un mot peut être rembourré avec des octets pour avoir un tel alignement.


" Le caractère également est parfois aligné sur une taille de mot (4 octets ou plus) compilateurs " peut introduire un rembourrage dans une structure pour une raison quelconque. Par définition, Char a une exigence d'alignement de 1. Cela signifie qu'un char peut mentir à n'importe quelle adresse, par définition. Donc, si les compilateurs ajoutent un remplissage de sorte qu'un char soit aligné, il n'est pas d'obéir à une exigence d'alignement . Quels compilateurs font cela, BTW?


" Ce n'est pas illégal, et est une adresse de l'opérateur, vous n'utilisez pas réellement la valeur pointée " Je pense que je sais ce que le & fait. Avant de prendre l'adresse, vous avez une Dréréférence . Une déréence n'est pas valide si le pointeur déréférencé ne pointe pas d'un objet . C'est vraiment élémentaire: dans l'ordre de f (g (x)) pour être bien défini, g (x) doit être bien défini et F (Y) a pour bien défini (où y est la valeur du résultat g (x) ). Il n'y a rien ici même légèrement subtil.


" La mise en oeuvre de la liste liée générique en C utilise cette macro exacte (dans le noyau Linux aussi bien chercher conteneur_of macro). " Vous ne pouvez pas prendre de code de Linux comme une preuve que quelque chose est bien défini C. Le noyau Linux n'est même pas écrit en c.


Laissez-nous Continuez cette discussion en chat


Note de modérateur Certains commentaires sous cette réponse ont été supprimés car ils se dégradaient dans le bruit. Veuillez garder des commentaires constructifs, professionnels et sur le sujet


"Voici le lien pour vous juste au cas où" lxr.linux.no/#linux+v3.1.2/include/linux/stddef.h#l20 Il est très intéressant de noter que s'il y a une macro intégrée __ compiler_offsetof < / code>, le offsetof macro n'impliquera pas une déréférence de pointeur nulle.



10
votes

4 commentaires

J'ai oublié de mentionner l'attribut emballé bien que je me suis allongé +1


J'essaie d'écrire un code qui fonctionne sur quelques plates-formes différentes. Je veux accéder à une structure exportée par un module différent, non écrite par moi-même et à laquelle je n'ai pas d'en-tête. Sur chaque plate-forme, les membres que je veux accéder sont sur différents décalages, je souhaite que le décalage soit une macro définie par le système de construction pour chaque plate-forme ... Votre solution ie ce que je suis en train de utiliser, mais je voulais savoir s'il y a est quelque chose plus clair


@T_Z En fait, je pense que c'est la seule façon de le faire, à moins que vous ne l'économisez pas dans un tampon et que vous effectuez les décalages à partir de là qui vous obtiendrez le même résultat bien plus compliqué.


@T_Z Je ne pense pas que l'utilisation d'une structure est le meilleur choix; Je ferais une fonction (ou plus) pour analyser cette structure en fonction de la plate-forme. De cette façon, je pouvais éviter de faire des astuces de compilation, ce qui, à mon avis, augmente la complexité du système de construction.



0
votes

Je ne suggère pas de faire cela; Les structures ne sont pas destinées à ce type de manipulation de données. Si vous devez modifier les données à un emplacement spécifique, utilisez un pointeur correctement dactylographié pour apporter les changements de cette façon. L'ajout de structures dans le mélange ajoute simplement une complexité sans aucun avantage.


0 commentaires

2
votes

J'ai envisagé l'option de rembourrage mentionnée sur les commentaires ici, mais cela me demande de faire des calculs ennuyeux chaque fois que je souhaite ajouter un membre.

En ce qui concerne les calculs ennuyeux, vous pouvez simplement générer la déclaration de votre structure à l'aide de votre langage de script préféré: xxx

sorties: xxx


0 commentaires

3
votes

Une solution utilisant un rembourrage et un syndicat tel que proposé dans d'autres réponses: xxx

sortie: xxx


0 commentaires

1
votes

J'écrirais une classe qui enveloppe un pointeur:

class whateverPtr {
    unsigned char *p;

public:
    whateverPtr(void *p) : p(reinterpret_cast<unsigned char *>(p) { }

    uint32_t getBar() const { return read_uint32(0xdc); }

private:
    uint32_t read_uint32(unsigned int offset) {
        return p[offset] |
            (p[offset + 1] << 8) |
            (p[offset + 2] << 16) |
            (p[offset + 3] << 24);
    }
};


0 commentaires

0
votes

Je ne sais pas si cela correspond à vos besoins avec GCC, mais j'utilise cette solution tout le temps et cela fonctionne bien avec mon compilateur VS:

#define STR_MERGE_IMPL(a, b) a##b
#define STR_MERGE(a, b) STR_MERGE_IMPL(a, b)
#define MAKE_PAD(size) STR_MERGE(_pad, __COUNTER__)[size]
#define DEFINE_MEMBER_N(type, name, offset) struct {unsigned char MAKE_PAD(offset); type name;}

struct Foo
{
    union {
        DEFINE_MEMBER_N(int, bar, 0x8);
    };
};

Foo foo;
foo.bar++;


0 commentaires