The following code is from an existing application that has to be compiled in both C and C++. There's a macro:
/* 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))))
that is used as follows:
ISomeInterface *object;
CoCreateInstance(&CLSID_SomeInterfaceImpl, NULL,
CLSCTX_INPROC_SERVER, COMPTR(ISomeInterface, &object))));
here the idea is that the last two parameters of CoCreateInstance()
are IID&
and void**
and that macro grabs ISomeInterface**
and converts it to IID&
and void**
at the same time enforcing a compile-time check that the address passed in place of ISomeInterface**
is indeed an address of ISomeInterface*
pointer variable.
Okay, but what's the need for
((obj) + (sizeof((obj)-(type **)(obj))) \
- (sizeof((obj)-(type **)(obj)))
complex expression? I see that the type checking is enforced with (obj)-(type**)(obj)
subexpression. What's the need for adding and then subtracting the sizeof()
? And what's the need for casting to void*
before casting to void**
?
I suppose the same can be done as follows:
#define COMPTR(type, obj) &IID_##type, \
(void **)(sizeof((obj)-(type**)(obj)), obj)
here the first part of comma operator would contain a sizeof()
that would enforce the typecheck and evaluate to a constant, the second part would just yield the same pointer and the pointer would be cast to void**
.
What can the original macro do what the one I suggest can't? What's the need for those complications?
Maybe the original author wasn't aware of the comma operator? This is not exactly unheard of among C/C++ programmers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With