:::: MENU ::::

Получение следующего элемента связанного списка из структуры, на которую указывает связанный список

Иногда бывает ситуация когда мы имеем адрес элемента структуры и есть необходимость получить адрес структуры, в которой находится данный элемент. Такая ситуация имеет место например, когда мы получаем в очереди из связанных списков адрес следующего элемента связанного списка, который в свою очередь является еще и элементом структуры, адрес которой нам необходимо узнать.

Рассмотрим более подробно — в программе мы имеем:

// связанные списки
typedef struct _link_init
{
   struct _link_init * prev;
   struct _link_init * next;
} link_init;

// очередь задач
link_init task_queue;

// структура, на которую будет указывать связанный список
typedef struct _task_init
{
    uint8_t x;
    uint8_t y;
    uint16_t z;

    link_init task_queue; // очередь задач
} task_init;

task_init task_1;   
task_init task_2;
task_init task_3;

Создается очередь задач:

task_queue.next = &task_1.task_queue;
task_1.task_queue.next = &task_2.task_queue;
task_2.task_queue.next = &task_3.task_queue;

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

Сначала получаем смещение в структуре на столько, на сколько смещена очередь задач в структуре. (смещение получаем программно для того, чтобы каждый раз не менять его при увеличении/уменьшении переменных в структуре).

// используется для получения смещения элемента структуры от начала структуры
unsigned char *off;
off = (unsigned char*)(&((task_init*)0)->task_queue);

(каждая 1 - 1 байт)
(off = 5)
если был бы z, off = 3
если был бы x, off = 1

После того как узнали смещение, можно очень просто получить адрес структуры. А значит можно и обращаться к элементам данной структуры. Так для задачи 3:

task_init *task_this;
task_this = (task_init*)((uint8_t*)(task_2.task_queue.next) - off);
task_this->x = 2;

(task_this = task_3)
(task_3.x = 2)