Является ли этот метод маркировки указателя в стандартном стандарте C?
(Повторите отметку с указателем: где размер объекта означает, что ограниченное количество бит в его указателе всегда будет неиспользованным и может быть повторно использовано для других целей, например, для маркировки типа объекта.)
отличный ответ на мой предыдущий вопрос по этому вопросу подтвердил, что наивный метод преобразования указателей в целые числа и делать что-либо с этими целыми числами не могут технически быть использованы для работы (без учета его популярности на практике).
Подумав об этом еще немного, я думаю, что у меня есть решение, которое работает для конкретного случая, описанного в исходном вопросе (все объекты одного размера, все объекты выделены из одного массива "кучи" ). Может ли кто-то подтвердить мои рассуждения?
// given:
typedef Cell ...; // such that sizeof(Cell) == 8
Cell heap[1024]; // or dynamic, w/e
// then:
void * tagged = ((char *)&heap[42]) + 3; // pointer with tag 3 (w/e that means)
int tag = ((char *)tagged - (char *)heap) % sizeof(Cell); // 3
Cell * ptr = (Cell *)((char *)tagged - tag); // &heap[42]
В словах: не делается никаких предположений о целочисленном представлении указателя. Теги применяются путем индексирования байтов в указанном объекте. (Это, безусловно, разрешено.)
Вычитание указателя возвращает разность индексов двух объектов внутри одного массива. Адреса байтов в объектах должны быть смежными, и поэтому помеченное значение преобразуется в тег, получая индекс адресного байта и удаляя размер всех предыдущих ячеек из этого индекса; меченый указатель может быть восстановлен указателем на ячейку, удалив теперь известный сдвиг индекса.
Является ли это все совместимым и, следовательно, переносным методом маркировки указателя? Является ли вычитание указателя по-прежнему разрешено работать, если тип массива преобразуется в что-то еще, char в этом случае? Могу ли я использовать sizeof(Cell)
таким образом?
(Нет, я не знаю, почему эта техничность так много наводит на мой взгляд, да, переносимость легко достигается другими средствами.)
Ответы
Ответ 1
Единственное, на что я думаю, что вам нужно быть более осторожным, вот ваши целые типы. Не используйте int
:
- Правильный тип различий указателей -
ptrdiff_t
.
- результатом
sizeof
является size_t
неподписанный тип
- Вы выполняете
%
между size_t
type и ptrdiff_t
, поэтому результат, скорее всего, size_t
, поэтому значение без знака
- преобразование, что
size_t
в int
- это реализация, определенная (поэтому не переносная), обычно она просто отбрасывает бит высокого порядка
int
будет работать долгое время, но в тот день, когда вы используете его с очень большим массивом на 64-битном процессоре, вы пожалеете об этом (после нескольких дней отладки)