2016-01-12 3 views
2

Я смотрел на это intrusive linked list implementation in C, и есть какая-то арифметика указателя, которую я не могу скомпоновать.Указатель Арифметика для Intrusive Связанный список

Во-первых, эта функция и макроэлементов, которые инициируют узел ссылка:

#define LINK_INIT(linkptr, structure, member) \ 
    link_init(linkptr, offsetof(structure, member)) 

void link_init(link *lnk, size_t offset) { 
    lnk->next = (void*) ((size_t) lnk + 1 - offset); 
    lnk->prev = lnk; 
} 

Я понимаю, что lnk->next (void*) ((size_t) lnk + 1 - offset) является указателем на следующий структуры в связанном списке, но я не понимаю, почему добавление 1 позволяет указатель на работу по-прежнему, когда смещение - это количество байтов, смещающих член от начала структуры. В struct header definition авторе говорит, что младший бит используется в качестве дозорных для обозначения конца списка, и поэтому lnk->next указателя может быть & полукольцо с 1 до теста на конце:

// All nodes (=next) must be allocated on (at least) two-byte boundaries 
// because the low bit is used as a sentinel to signal end-of-list. 
typedef struct link { 
    struct link *prev; 
    void *next; 
} link; 

void* link_next(link *lnk) { 
    if ((size_t) lnk->next & 1) 
    return NULL; 
    return lnk->next; 
} 

Я Просто интересно, почему это вообще работает? Я смутно понимаю границы распределения, но, по-моему, недостаточно, чтобы понять, почему это работает.

+3

Очень плохой подход! Использование битов в указателе не должно выполняться, если у вас нет очень ограниченного ОЗУ целевого объекта. И тогда связанный список, скорее всего, неправильный подход. И для связанного списка это на самом деле ерунда. Просто используйте _null pointer_. – Olaf

+1

Как вы на самом деле выделили эти указатели? Это '//, потому что младший бит используется как контрольный сигнал, чтобы сигнализировать конец списка. Звучит очень странно. Я не верю, что вы можете (ab) использовать указатель таким образом. –

+2

Использование младшего бита указателя как часового - очень плохая идея, усугубленная приведением к 'size_t'. По крайней мере, бросьте на что-то разумное, например 'intptr_t'. – user3386109

ответ

0

Это работает, потому что большинство современных архитектур имеют 32-разрядную и даже 64-битную ширину, а указатели должны быть выровнены по 32-битным или 64-битным блокам; в этом случае значение int указателя обязательно кратно 32 или 64; так что по крайней мере это даже.

Но это не всегда так. Просто потому, что значение int указателя нечетное, не означает, что указатель недействителен. Это зависит от архитектуры.

Кроме того, при получении указателя «next» необходимо выполнить тест, чтобы вернуть правильное значение: NULL.

Неправильное предположение о значении указателя, дополнительных тестах и ​​рисках с неправильным использованием неверного указателя ... Почему бы не установить указатель на NULL в первую очередь?

+0

Спасибо за объяснение. Я думаю, что оригинальный автор реализовал связанный список, чтобы быть круговым, но я согласен, что это определенно сложная реализация. Я просто задавался вопросом, почему это вообще работает, но ваше объяснение имеет смысл. –