Как можно вычислить указатель на начало структуры из указателя, указывающего на член структуры переносимым способом?
Предполагать T1
а также T2
два типа и дается следующая структура:
struct s
{
T1 x;
T2 y;
}
Далее предположим, что у нас есть объект типа struct s
:
struct s a;
Исходя из этого, мы можем вычислить указатель на второй член структуры объекта:
T2 *q = &s.y;
То, что я ищу, это портативный способ расчета из q
указатель p
типа struct s *
такой, что p
указывает на объект a
,
3 ответа
Дано T2 *q = &s.y;
, затем char *x = (char *) q - offsetof(struct s, y);
определяет x
это указывает на первый байт s
, offsetof
макрос определяется в <stddef.h>
,
Можно ожидать struct s *p = (struct s *) x;
определить p
это указывает на s
в зависимости от того, насколько педантично кто-то хочет интерпретировать стандарт C. (Преобразование указателя в char
для указателя на структуру, это первый байт, который не определен стандартом в явном виде. Мы можем взять спецификацию стандарта, согласно которой указатель "преобразован обратно" в C 2018 6.3.2.3 7, в свой первоначальный тип, чтобы охватить этот случай.) Я ожидаю, что он будет работать во всех обычных реализациях C.
Ты ищешь container_of()
; из Википедии
#define container_of(ptr, type, member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)))
или более простой, но менее безопасный
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
В вашем случае вы бы применили его как
struct *s = container_of(q, struct s, y);
T2 *py = &z.y
T1 *px = (T1 *)((char *)py - ((char *)&z.y - (char *)&z.x));