Пожалуйста, объясните этот хардкорный макрос, который выполняет приведение типов и проверку типов

Следующий код взят из существующего приложения, которое должно быть скомпилировано как на C, так и на C ++. Есть макрос:

/* Type-checking macro to provide arguments for CoCreateInstance() etc.
 * The pointer arithmetic is a compile-time pointer type check that 'obj'
 * really is a 'type **', but is intended to have no effect at runtime. */
#define COMPTR(type, obj) &IID_##type, \
(void **)(void *)((obj) + (sizeof((obj)-(type **)(obj))) \
                - (sizeof((obj)-(type **)(obj))))

, который используется следующим образом:

ISomeInterface *object;
CoCreateInstance(&CLSID_SomeInterfaceImpl, NULL,
     CLSCTX_INPROC_SERVER, COMPTR(ISomeInterface, &object))));

здесь идея состоит в том, что последние два параметра CoCreateInstance () - это IID & и void ** , и этот макрос захватывает ISomeInterface ** и преобразует его в IID & и void ** в то же время принудительная проверка во время компиляции, что адрес, переданный вместо ISomeInterface ** , действительно является адресом переменной указателя ISomeInterface * .

Хорошо, но зачем нужно

((obj) + (sizeof((obj)-(type **)(obj))) \
     - (sizeof((obj)-(type **)(obj)))

сложное выражение? Я вижу, что проверка типов выполняется с помощью подвыражения (obj) - (type **) (obj) . Зачем нужно складывать, а затем вычитать sizeof () ? И зачем нужно приведение к void * перед приведением к void ** ?

Я полагаю, то же самое можно сделать следующим образом:

#define COMPTR(type, obj) &IID_##type, \
(void **)(sizeof((obj)-(type**)(obj)), obj)

здесь первая часть запятой оператор будет содержать sizeof () , который будет принудительно выполнять проверку типов и вычислять константу, вторая часть просто выдаст тот же указатель, и указатель будет приведен к void ** .

Что может делать исходный макрос, а тот, который я предлагаю, не может? Зачем нужны эти осложнения?

9
задан sharptooth 29 June 2011 в 10:27
поделиться