这个c++宏在做什么

What is this c++ macro doing?

本文关键字:什么 c++ 这个      更新时间:2023-10-16

我不明白下面的宏在做什么?如果有人能帮我看,我将不胜感激。

#define BASE_OFFSET(ClassName,BaseName)
(DWORD(static_cast < BaseName* >( reinterpret_cast
< ClassName* >(Ox10000000)))-Ox10000000)

如果有人想知道它是从哪里来的,它来自Don-Box Book Essential COM的第三章,他正在使用接口表构建QueryInterface函数,上面的宏以某种方式被用来找到指向类的接口vtable的指针,其中class是实现BaseName的ClassName,尽管我不知道它是如何做到的。

它告诉编译器:"假设在0x10000000处有一个ClassName对象。相对于0x10000000",BaseName数据将从该对象的何处开始?

想象一个具有多个基的类对象的内存布局:

class A: B, C{};

在构成A对象的内存块中,有属于B的数据块,也有属于C的数据块和特定于A的数据。由于至少一个基数据的地址不能与整个类实例的地址相同,因此传递给不同方法的this指针的数值需要有所不同。宏检索差值。

EDIT:按照惯例,指向vtable的指针是任何具有虚拟函数的类中的第一个数据成员。因此,通过找到基础数据的地址,就可以找到其vtable指针的地址。

现在,关于类型转换。通常,当您键入指针时,操作在内部是琐碎的——地址的数值不取决于它指向的类型;数据类型的概念只存在于C级。不过,有一个重要的例外——当您使用多个继承来强制转换对象指针时。正如我们刚刚讨论的那样,需要传递给基类方法的this指针可能在数值上与派生对象的指针不同。

因此,static_cast和interpret_cast之间的区别巧妙地捕捉到了这种差异。当你使用reinterpret_cast时,你告诉编译器:"我更清楚。取这个数值,并将其解释为指向我所说内容的指针"。这是一种蓄意颠覆类型体系的行为,危险,但偶尔也有必要。根据定义,这种类型的转换是琐碎的——因为你这么说

我所说的"琐碎"是指指针的数值不会改变。

static_cast是一个更高级的构造。在这种特殊的情况下,您将在对象及其基础之间进行投射。在C++类规则下,这是一个合理、安全的类型转换,但在数值上可能是不平凡的。这就是宏使用两种不同类型转换的原因。static_cast不违反类型系统。

概括一下:

reinterpret_cast<ClassName* >(OxlOOOOOOO)

是不安全的操作。它返回一个指向伪对象的伪指针,但这没关系,因为我们从不取消引用它

static_cast<BaseName*>(...)

是一个安全的操作(具有讽刺意味的是,使用了一个不安全的指针)。这是发生非平凡指针类型转换的部分。

(DWORD(...)-OxlOOOOOOO)

是纯粹的算术。这就是不安全加倍的地方:我们不把指针用作指针,而是把它投射回一个整数,忘记了它曾经是一个指针。

最后一个阶段可以等效地改写为:

((char*)(...)-(char*)OxlOOOOOOO)

如果这更有意义的话。

关于魔术0x10000000常数的备注。

如果该常量为0,GCC将显示警告-Winvalid偏移量为(当然,如果启用了它)。也许其他编译器也会这样做。