Поиск смещения элемента структуры в 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