Поиск смещения элемента структуры в c

struct a
{
    struct b
    {
        int i;
        float j;
    }x;
    struct c
    {
        int k;  
        float l;
    }y;
}z;

Может ли кто-нибудь объяснить мне, как найти смещение int k чтобы мы могли найти адрес int i?

Ответ 1

Используйте offsetof() чтобы найти смещение от начала z или от начала x.

offsetof() - смещение элемента структуры

СИНТАКСИС

   #include <stddef.h>

   size_t offsetof(type, member);

offsetof() возвращает смещение члена поля от начала типа структуры.

ПРИМЕР

   #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);
   }

Вы получите следующий результат в Linux, если вы скомпилируете GCC:

       offsets: i=0; c=4; d=8 a=16
       sizeof(struct s)=16

Ответ 2

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.xi ссылается на поле i в структуре x в структуре foo. &foo.xi дает вам адрес поля foo.xi Аналогично, &foo.yk дает вам адрес foo.yk; &foo дает вам адрес структуры foo.

Вычитание адреса foo из адреса foo.xi дает вам смещение от foo до foo.xi

Как говорит Гангадхар, вы можете использовать макрос offsetof() вместо арифметики указателя, которую я дал. Но хорошо сначала понять арифметику указателя.

Ответ 3

Прошло 3 года с тех пор, как вопрос был задан, я добавляю свой ответ для полноты картины.

Хакерский способ получить смещение члена структуры выглядит следующим образом

printf("%p\n", (void*)(&((struct s *)NULL)->i));

Это не выглядит красиво, я не могу думать ни о чем в чистом C (который может дать вам смещение члена, не зная ничего о структуре. Я считаю, что offsetof макроса определено таким образом.

Для справки, этот метод используется в ядре Linux, проверьте макрос container_of:

http://lxr.free-electrons.com/source/scripts/kconfig/list.h#L18

Более подробное объяснение можно найти в этой статье:

http://radek.io/2012/11/10/magical-container_of-macro/

Ответ 4

Как уже было предложено, вы должны использовать макрос offsetof() из <stddef.h>, что дает смещение как значение size_t.

Например:

#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;
}

Пример вывода:

k = 0 8; i = 0 0

Ответ 5

Вот общее решение:

#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