LINUX.ORG.RU

Получение адреса структуры по адресу ее поля

 ,


1

2

Кто-нибудь, подскажите почему адреса не равны?

struct something {
    int  foo;
    char ch;
    int  bar;
};

int main(void)
{
    struct something st;
    printf("       st addr: %lx\n", &st);
    printf("st addr by foo: %lx\n", (size_t)&st.foo - (size_t)&(((struct something*)0)->foo));
    printf("st addr by foo: %lx\n", &st.foo - &(((struct something*)0)->foo));
    return 0;
}

Выхлоп:

st addr: 7fff5fbff7e0
st addr by foo: 7fff5fbff7e0
st addr by foo: 1fffd7effdf8



Последнее исправление: cetjs2 (всего исправлений: 1)

В последнем printf вычитаются указатели, а не числа. Арифметика с указателями работает по иным правилам, нежели с числами. Результатом является расстояние между указателями в int-ах, а не в байтах.

см. «C pointer arithmetic».

ringill
()
Последнее исправление: ringill (всего исправлений: 1)
Ответ на: комментарий от ringill

все понял. во втором это не адрес, а число интовых переменных между структурой и нулевым адресом.

Спасибо)

maksspaces
() автор топика
Ответ на: комментарий от max_lapshin

printf(«st addr by foo: %lx\n», (size_t)&st.foo - (size_t)&(((struct something*)0)->foo));
printf(«st addr by foo: %lx\n», &st.foo - &(((struct something*)0)->foo));

В первом да, во втором:

число интовых переменных между структурой и нулевым адресом.

maksspaces
() автор топика

Если не напрягает gcc-изм возьми безопасную реализацию из ядра

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})
anonymous
()
Ответ на: комментарий от maksspaces

Объясни, пожалуйста, почему &(((struct something*)0)->foo) не ноль?

Мне кажется, что здесь записано смещение в байтах поля foo от начала структуры struct something, которую удобно разместили по свободному адресу 0.

Поле foo идет первым, поэтому с большой вероятностью компилятор положит его в начале структуры без паддинга.

Разве нет?

max_lapshin ★★★★★
()
Ответ на: комментарий от max_lapshin

&(((struct something*)0)->foo) не ноль?

ноль, только это не число, а адрес

(struct something*)0 // взяли адрес 0 и привели его к указателю на struct something
((struct something*)0)->foo // получили поле foo по этому указателю
&(((struct something*)0)->foo) // получили адрес foo

Просто у foo и адрес и смещение == 0, по этому

&st.foo - 0 == &st.foo
но
&st.foo - (int*)0 == число интов между ними

maksspaces
() автор топика
Ответ на: комментарий от maksspaces

вот тут ты меня сейчас просто убил.

Я даже помыслить не мог, что разница двух указателей — это количество интов.

Но это же цифра вообще ни о чём. Инт часто меняющегося размера.

Вот я сейчас сижу и просто вахуе, если честно. Пытаюсь вспомнить, сколько нерабочего кода я оставил:

struct A {
  char c;
  int b;
};

int main() {
  struct A l[4];
  printf("A size: %d\n", (int)sizeof(struct A));
  printf("delta: %d\n", &(l[1]) - &(l[0]));
}
$ ./check 
A size: 8
delta: 1
max_lapshin ★★★★★
()
Ответ на: комментарий от max_lapshin

не обязательно в интах будет размер. если указатель привести к чему нибудь другому то цифра будет другая

maksspaces
() автор топика
Ответ на: комментарий от maksspaces

можешь пояснить, почему в коде который я привел, во второй строчке 1, а не 2?

ведь инт то 4 байта и между двумя соседними структурами будет разница в 8 байт или два инта.

max_lapshin ★★★★★
()
Ответ на: комментарий от max_lapshin

Потому что арифметика указателей. Возвращается частное от (разность указателей как чисел) и (размер типа данных, на который указывает указатель). Т. е. по смыслу — количество объектов (не в смысле объектов C++, просто каких-то объектов) между указателями, если считать их указателями на элементы некоторого массива объектов.

Kiborg ★★★
()
Ответ на: комментарий от max_lapshin

Как уже говорил выше: разность указателей == кол-во элементов между ними, соответствующего типа.

можешь пояснить, почему в коде который я привел, во второй строчке 1, а не 2?

А потому, что &l[0] = это адрес СТРУКТУРЫ, а не инта в ней, тоже самое для &l[1], по этому, разность указателей этих, это кол-во СТРУКТУР между ними, а не интов.

Это кол-во - зависит только от типа указателя. И он сейчас не int*, а struct A*

maksspaces
() автор топика
Ответ на: комментарий от max_lapshin

можешь пояснить, почему в коде который я привел, во второй строчке 1, а не 2?

2 будет если тип указателя поменять:

printf("%lu\n", (int*)&a[1] - (int*)&a[0]);

maksspaces
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.