struct a
{
struct b
{
int i;
float j;
}x;
struct c
{
int k;
float l;
}y;
}z;
Quelqu'un peut-il m'expliquer comment trouver le décalage de int k
afin que nous puissions trouver l'adresse de int i
?
Utilisez offsetof()
pour trouver l'offset depuis le début de z
ou depuis le début de x
.
offsetof()
- décalage d'un membre de la structure
SYNOPSIS
#include <stddef.h>
size_t offsetof(type, member);
offsetof()
renvoie le décalage du membre de champ depuis le début du type de structure.
EXEMPLE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
struct s {
int i;
char c;
double d;
char a[];
};
/* Output is compiler dependent */
printf("offsets: i=%ld; c=%ld; d=%ld a=%ld\n",
(long) offsetof(struct s, i),
(long) offsetof(struct s, c),
(long) offsetof(struct s, d),
(long) offsetof(struct s, a));
printf("sizeof(struct s)=%ld\n", (long) sizeof(struct s));
exit(EXIT_SUCCESS);
}
Vous obtiendrez la sortie suivante sur un Linux, si vous compilez avec GCC:
offsets: i=0; c=4; d=8 a=16
sizeof(struct s)=16
struct a foo;
printf("offset of k is %d\n", (char *)&foo.y.k - (char *)&foo);
printf("offset of i is %d\n", (char *)&foo.x.i - (char *)&foo);
foo.x.i
Fait référence au champ i
dans la structure x
dans la structure foo
. &foo.x.i
Vous donne l'adresse du champ foo.x.i
. De même, &foo.y.k
Vous donne l'adresse de foo.y.k
; &foo
Vous donne l'adresse de la structure foo
.
La soustraction de l'adresse de foo
de l'adresse de foo.x.i
Vous donne le décalage de foo
à foo.x.i
.
Comme le dit Gangadhar, vous pouvez utiliser la macro offsetof()
plutôt que l'arithmétique du pointeur que j'ai donnée. Mais il est bon de comprendre d'abord l'arithmétique du pointeur.
Cela fait 3 ans que la question a été posée, j'ajoute ma réponse par souci d'exhaustivité.
La manière hacky d'obtenir le décalage d'un membre struct va comme ceci
printf("%p\n", (void*)(&((struct s *)NULL)->i));
Cela n'a pas l'air joli, je ne peux penser à rien en C pur (qui peut vous obtenir le décalage du membre, sans rien savoir de la structure. Je crois que la macro offsetof
est définie dans ce mode.
Pour référence, cette technique est utilisée dans le noyau linux, consultez le container_of
macro:
http://lxr.free-electrons.com/source/scripts/kconfig/list.h#L18
Une explication plus élaborée peut être trouvée dans cet article:
Comme déjà suggéré, vous devez utiliser la macro offsetof()
de <stddef.h>
, ce qui donne le décalage en tant que size_t
valeur.
Par exemple:
#include <stddef.h>
#include <stdio.h>
#include "struct_a.h" /* Header defining the structure in the question */
int main(void)
{
size_t off_k_y = offsetof(struct c, k);
size_t off_k_z = offsetof(struct a, y.k);
size_t off_i_x = offsetof(struct b, i);
size_t off_i_z = offsetof(struct a, x.i);
printf("k = %zu %zu; i = %zu %zu\n", off_k_y, off_k_z, off_i_x, off_i_z);
return 0;
}
Exemple de sortie:
k = 0 8; i = 0 0
Voici une solution générique:
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define GNUC_PREREQ(minMajor, minMinor) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((minMajor) << 16) + (minMinor))
#else
# define GNUC_PREREQ 0
#endif
#if GNUC_PREREQ(4, 0)
# define OFFSETOF(type, member) ((int)__builtin_offsetof(type, member))
#else
# define OFFSETOF(type, member) ((int)(intptr_t)&(((type *)(void*)0)->member) )
#endif