Comment puis-je obtenir/définir une struct membre par compensation
Ignorant rembourrage/problèmes d'alignement et compte tenu de la structure suivante, quelle est la meilleure façon d'obtenir et de définir la valeur de member_b sans utiliser le nom de membre.
struct mystruct {
int member_a;
int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));
Mettre une autre manière; Comment vous exprimer la suivante en termes de pointeurs/offsets:
s->member_b = 3;
printf("%i",s->member_b);
Ma conjecture est à
- calculer le décalage par trouver le sizeof l'member_a (
int
) - fonte de la structure à un seul mot de type pointeur (
char
?) - créer un
int
pointeur et réglez l'adresse (pour les*charpointer + offset
?) - utiliser mon
int
pointeur pour définir le contenu de la mémoire
mais je suis un peu confus au sujet de la conversion vers un type char ou si quelque chose comme memset
est plus adéquat ou si en général je suis aproching ce totalement faux.
Bravo pour toute aide
- Pourquoi voulez-vous faire cela?
- Je suis combler un écart entre un environnement de script et les C-extensions, (pensez à Python, C-Types), et je suis à la définition et à l'accès aux structures lors de l'exécution.
- Alors vous êtes la génération de code C? Dans ce cas, vous pouvez générer du code C pour accéder les membres de la structure aussi. Fait que j'ai mal compris?
Vous devez vous connecter pour publier un commentaire.
L'approche que vous avez décrit est à peu près correct, bien que vous devriez utiliser
offsetof
au lieu de tenter de comprendre le décalage sur votre propre. Je ne suis pas sûr de savoir pourquoi vous mentionnermemset
-- il définit le contenu d'un bloc à une certaine valeur, ce qui semble tout à fait sans rapport avec la question à portée de main.Voici un peu de code pour montrer comment il fonctionne:
((struct mystruct *)p)->member_b = 3;
La technique entière:
Obtenir le décalage à l'aide de offsetof:
Obtenir l'adresse de votre structure en tant que char * pointeur.
Ajouter un offset à la structure de l'adresse, la fonte de la valeur à un pointeur sur le type et le déréférencement:
Ignorant de rembourrage et de l'alignement, comme vous l'avez dit...
Si les éléments que vous avez pointant vers sont entièrement d'un seul type, comme dans votre exemple, vous pouvez juste lancer la structure, du type désiré et de le traiter comme un tableau:
Il est possible de calculer le décalage basé sur la structure et la valeur NULL comme pointeur de référence
e.g " &(((type *)0)->champ)"
Exemple:
Dans cet exemple particulier, vous pouvez vous adresser par
*((int *) ((char *) s + sizeof(int)))
. Je ne suis pas sûr de savoir pourquoi vous voulez, donc je suis en supposant un but didactique, donc l'explication de la façon suivante.Les bits de code se traduit comme: prenez la mémoire commençant à l'adresse s et de la traiter comme de la mémoire pointant vers
char
. À cette adresse, ajoutersizeof(int)
char
-morceaux - vous obtenir une nouvelle adresse. Prendre la valeur de l'adresse ainsi créé et la traiter comme uneint
.Remarque que l'écriture
*(s + sizeof(int))
donnerait l'adresse às
plussizeof(int)
sizeof(mystruct) morceauxEdit: comme par Andrey commentaire, à l'aide de offsetof:
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
Edit 2: j'ai remplacé tous les
byte
s avecchar
s commesizeof(char)
est garantie 1.byte
et paschar
? Aussi((byte *) s + sizeof(int))
est de typebyte *
, qui est le même quechar *
, sorte de déférence, il (peut) pas de vous donner unint
- sisizeof(int) != sizeof(char)
. Vous avez besoin d'un plâtre pourint *
avant d'être déréférencé.member_b
champ, vous devez ajouteroffsetof(mystruct, member_b)
qui n'est pas nécessairement le même quesizeof(int)
.byte
? La norme ne définit pas elle. Aussi, sisizeof(byte) != sizeof(char)
, alors vous voulez certainementchar
et pasbyte
dans votre code depuissizeof(char)
est 1.offsetof
est mieux, j'ai été de tenter de "corriger" laura du code sans changer sa forme (je sais même alors, il n'est pas correct).char
. OIE, dans la mesure du C (et C++) de soins, 'octet' et de 'char' sont pratiquement interchangeables.offsetof(struct mystruct, member_b)
, ou mieux:((struct mystruct *)s)->member_b = 3;
typedef
, le casting(byte *)
ne veut rien dire en C.((struct mystruct *)s)->member_b = 3;
.Il sons de vos commentaires que ce que vous êtes vraiment en train de faire est de l'emballage et déballage de tout un tas de différents types de données dans un seul bloc de mémoire. Alors que vous peut s'en tirer avec faire avec pointeur direct jette, comme la plupart des autres réponses ont suggéré:
Le problème est que c'est non portable. Il n'y a pas en général de façon à s'assurer que les types sont stockés dans votre bloc avec l'alignement correct de la, et certaines architectures ne peut tout simplement pas les charges ou les magasins de non-alignées adresses. Dans le cas particulier où la mise en page de votre bloc est défini par une déclaration de structure, il sera OK, parce que la structure de mise en page comprendra le nécessaire rembourrage pour assurer l'alignement à droite. Cependant, comme vous ne pouvez pas accéder aux membres par leur nom, on dirait que ce n'est pas vraiment ce que vous faites.
Pour ce faire de façon portable, vous avez besoin d'utiliser
memcpy
:(similaire pour les autres types).