Я не могу понять, почему они вычитают два указателя.Не вернет ли оно то же значение (ноль)?
Да, но только если член base
является первым в структуре.l_base
- это адрес структуры, тогда как s_base
- это адрес элемента base
в этой структуре, оба преобразуются в указатели в unsigned8
.
C99 и более поздние, в явном виде говорится, что еслиbase
является первым членом в структуре, он имеет тот же адрес, что и структура.
Это связано с Linux IPC?
Нет, не то, что яможно увидеть.
Однако существует неопределенно похожий шаблон, связанный с межпроцессным взаимодействием с общей памятью.
Допустим, у вас есть struct shared_data *shared
, который указывает на разделяемую память.
Поскольку каждый процесс имеет свое собственное виртуальное адресное пространство, хотя содержимое из shared
является общим, каждый процесс может иметь его по своему адресу, то есть самому значению shared
.может варьироваться.
Это означает, что использование указателей внутри разделяемой памяти в принципе бесполезно.То, что конкретное значение указателя в одном процессе указывает на определенную часть разделяемой памяти, не означает, что оно применяется во всех процессах.
Вместо указателей необходимо хранить смещения относительно shared
, так что 0
относится к первому адресу в области общей памяти и так далее.(Или какая-то другая аналогичная схема относительно начала разделяемой памяти.)
Для этого вы можете увидеть код, подобный
intptr_t shared_offset = (intptr_t)shared;
Тип intptr_t
- это портативный POSIX-совместимый тип.В Linux вы можете использовать long
.Проблема в том, что существует старый код, который использует int
, и даже старые книги, которые используют int
в своих примерах, но он не будет работать правильно на 64-битных архитектурах, таких как более новые компьютеры Intel и AMD, например.
В любом случае, чтобы преобразовать байтовое смещение, скажем, shared[5].next
в указатель в footype
, скажем, footype *foo
, необходимо использовать
foo = (footype *)((char *)shared + shared[5].next);
или
foo = (footype *)(shared_offset + shared[5].next);
Оба эквивалентны;первый использует непосредственно указатель shared
, а второй использует переменную shared_offset
.
Обратное преобразование из foo
в смещение, например,
offset = (ptrdiff_t)((char *)foo - (char *)shared);
или
offset = (intptr_t)foo - shared_offset;
Этот подход хрупок в том смысле, что для правильного написания всех этих выражений требуется много усилий, в то же время обеспечивая правильность базовой логики.(Я думаю, что это похоже на попытку постукивания одной рукой и одновременного рисования круга другой. Большинству людей требуется много практики, чтобы сделать это правильно.)
Если это вообще возможно, этоЛучше использовать массив и индексирование массива, а не смещать начало общей памяти.
Я видел, как этот метод смещения использовался разумно, когда размер каждого элемента менялся.Даже тогда обычно существуют лучшие алгоритмические подходы.