【问题标题】:What's the use of _ATL_PACKING constant when computing distance from the start of object?计算距对象起点的距离时,_ATL_PACKING 常量有什么用?
【发布时间】:2011-06-28 04:41:59
【问题描述】:

ATL 功能 a set of macros for so-called COM maps。 COM 映射是一个表,它将接口 GUID 与要添加到 this 指针以获取相应子对象的偏移量相关联 - 整个东西作为 explicit static_cast for the upcast inside IUnknown::QueryInterface() 的替代品。

地图条目是使用offsetofclass宏构建的:

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

为了便于阅读,我将其重写为以下伪代码“函数”:

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

看起来很合理 - 它获得一个指向虚构派生对象的指针,然后执行显式 static_cast 来移动指针,然后计算这些虚构对象之间的距离。

问题是为什么常数 8 在那里?为什么我们需要这个常数,为什么选择 8?

【问题讨论】:

    标签: c++ com macros casting atl


    【解决方案1】:

    存在非零常量是因为宏不适用于空指针。我们知道空指针的值是一个空指针常量,其计算结果为0

    C++ 标准 4.10/1 指针转换 [conv.ptr]:

    空指针常量是一个整数 常量表达式 (5.19) 的右值 求值为零的整数类型。一种 可以转换空指针常量 指向指针类型;结果是 该类型的空指针值并且是 可与其他所有值区分开来 指向对象的指针或指向的指针 函数类型....

    这是关于从派生类转换为基类指针类型的相关条款:

    C++ 标准 4.10/3 指针转换 [conv.ptr]:

    “指向 cv D 的指针”类型的右值, 其中 D 是类类型,可以是 转换为类型的右值 “指向 cv B 的指针”,其中 B 是基数 D 类(第 10 条)。如果 B 是 无法访问(第 11 条)或模棱两可 (10.2) D 的基类,一个程序 需要这种转换是 格式不正确。结果 转换是指向基数的指针 派生类的类子对象 目的。 空指针值为 转换为空指针值 目的地类型。

    基本上,空指针会阻止指针算术在派生到基址的转换期间启动;你只会得到另一个空指针。该算法用于在此类转换期间“修复”非空指针,使其指向正确的子对象。 offsetofclass 宏依赖此算法来确定偏移量。

    使用的数字8 是任意的。您可以在那里使用任何数字,例如 14,只要它不为零。

    【讨论】:

    • @sharptooth:类定义本身中有足够的信息,编译器可以在编译时计算出它们的大小和偏移量。 offsetofclass 宏中的表达式计算结果为常量,因此编译器应该能够折叠算术。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 2014-11-29
    相关资源
    最近更新 更多