Какая польза от константы _ATL_PACKING при вычислении расстояния от начала объекта? - PullRequest
1 голос
/ 16 февраля 2011

ATL содержит набор макросов для так называемых COM-карт . COM-карта - это таблица, которая связывает GUID интерфейса со смещением, которое нужно добавить к указателю this, чтобы получить доступ к соответствующему подобъекту - весь материал работает как замена явного static_cast для восходящего потока внутри IUnknown::QueryInterface().

Записи карты строятся с использованием макроса offsetofclass:

#define _ATL_PACKING 8
#define offsetofclass(base, derived)\
    ((DWORD_PTR)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)

, которую я напишу как псевдокод «function» для удобства чтения в этом вопросе:

derived* derivedPointer = (derived*)_ATL_PACKING;
base* basePointer = static_cast<base*>(derivedPointer);
DWORD_PTR offset = (DWORD_PTR)(basePointer)-_ATL_PACKING;

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

Вопрос в том, почему константа 8 там? Зачем нам нужна эта константа и почему она выбрана равной 8?

1 Ответ

3 голосов
/ 16 февраля 2011

Ненулевая константа существует потому, что макрос не работает с нулевыми указателями. Мы знаем, что значение нулевого указателя является константой нулевого указателя, которая оценивается как 0:

C ++ Стандарт 4.10 / 1 Преобразование указателя [conv.ptr]:

Константа нулевого указателя является интегралом константное выражение (5.19) целочисленный тип, который оценивается в ноль. константа нулевого указателя может быть преобразована на указатель типа; результатом является значение нулевого указателя этого типа и является отличается от любого другого значения указатель на объект или указатель на тип функции ....

Это релевантное предложение в отношении преобразования из производного класса в тип указателя базового класса:

C ++ Стандарт 4.10 / 3 Преобразования указателей [conv.ptr]:

Значение типа «указатель на cv D» где D - тип класса, может быть преобразован в значение типа «Указатель на cv B», где B является базой класс (пункт 10) D. Если B является недоступный (пункт 11) или неоднозначный (10.2) базовый класс D, программа, которая требует этого преобразования плохо сформирован. Результат преобразование является указателем на базу подобъект класса производного класса объект. Значение нулевого указателя: преобразуется в значение нулевого указателя тип пункта назначения.

В основном нулевые указатели предотвращают срабатывание арифметики указателей во время преобразования из производной в базовую; вы просто получите еще один нулевой указатель. Арифметика используется для «исправления» ненулевых указателей во время таких преобразований, чтобы указывать на соответствующий подобъект. Макрос offsetofclass зависит от этой арифметики для определения смещения.

Используемое число 8 является произвольным. Вы могли использовать любое число, например, 1 или 4, если оно не равно нулю.

...