请解释这个执行强制转换和类型检查的核心宏

时间:2011-06-29 10:27:36

标签: c++ c macros types casting

以下代码来自必须在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&和{ {1}}同时强制执行编译时检查,代替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()

原始宏可以做什么我建议的不可以?这些并发症有什么需要?

2 个答案:

答案 0 :(得分:5)

也许原作者不知道逗号运算符?这在C / C ++程序员中并非闻所未闻。

答案 1 :(得分:4)

也许原作者不知道功能模板。这个宏乞求被功能模板取代。

显然,CoCreateInstance的第四个参数是指向IID类型的某个全局对象的指针,该对象属于手头的type(COMPTR的类型参数)。 CoCreateInstance的第五个也是最后一个参数应该是type**指针。

相反,函数CoCreateInstancevoid**(yech!)指针作为最后一个参数,通过转换假定的type**指针获得。强制转换为void*作为中介,因为任何指针都可以转换为void *指针。

在该COMPTR宏中没有保护,可以传递double*指针,甚至是long long(不是指针!)作为CoCreateInstance的第五个参数。当然,如果原作者使用C ++非常擅长,输入安全性就会避免这种混乱。相反,他/她决定采用void *指针路线并将保护放在宏中。

愚蠢行为:sizeof的参数是指针差异表达式(obj)-(type**)(obj)。如果objtype**指针,则为0(类型为ptrdiff_t)。如果obj是其他内容,则此指针差异表达式是错误的。因此,有两种情况,objtype**指针,或者不是。{/ p>

情况1,objtype**指针:指针差异表达式有效,因此CoCreateInstance的最后一个参数扩展为(void**)(void*)(obj+8-8),假设64位机器。 (+ 8-8在32位机器上变为+ 4-4。)无论机器大小如何,都会添加和减去偏移量,留下原始指针。

情况2,obj不是type**指针:指针差异表达式格式错误,因此代码无法编译。