(Повторите отметку с указателем: где размер объекта означает, что ограниченное количество бит в его указателе всегда будет неиспользованным и может быть повторно использовано для других целей, например, для маркировки типа объекта.)
отличный ответ на мой предыдущий вопрос по этому вопросу подтвердил, что наивный метод преобразования указателей в целые числа и делать что-либо с этими целыми числами не могут технически быть использованы для работы (без учета его популярности на практике).
Подумав об этом еще немного, я думаю, что у меня есть решение, которое работает для конкретного случая, описанного в исходном вопросе (все объекты одного размера, все объекты выделены из одного массива "кучи" ). Может ли кто-то подтвердить мои рассуждения?
// 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)
таким образом?
(Нет, я не знаю, почему эта техничность так много наводит на мой взгляд, да, переносимость легко достигается другими средствами.)