当从对象的开始计算距离时,使用_ATL_PACKING常量是什么? [英] What's the use of _ATL_PACKING constant when computing distance from the start of object?
问题描述
ATL的功能包括一组宏-called COM maps 。 COM映射是一个表,它将一个接口GUID与一个偏移相关联,该偏移将被添加到这个
指针以获得相应的子对象 - 整个东西作为显示 static_cast
为 IUnknown :: QueryInterface() / code>
。
地图条目是使用 offsetofclass
宏建立的: / p>
#define @L_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?
非零常数存在,不使用空指针。我们知道一个空指针的值是一个空指针常量,其计算结果为 0
:
C ++标准4.10 / 1指针转换[conv.ptr]:
空指针常数是整数
常量表达式(5.19)
的整数类型的值,计算结果为零。 A
空指针常量可以将
转换为指针类型;结果是该类型的
空指针值,并且
与每个其他值区分开。
指向对象的指针或指向
函数类型的指针。
这是与从派生类转换为基类指针类型相关的子句:
C ++标准4.10 / 3指针转换[conv.ptr]:
类型的右值指向cv D的指针,
其中D是类类型,可以是
转换为类型
的指针指向cv B的指针,其中B是基数
如果B是一个
不可访问(第11条)或不确定的
(10.2)D的基类,一个程序,
需要这个转换是
形成不良。
转换的结果是指向派生类
对象的基本
类子对象的指针。 空指针值
转换为
的空指针值目标类型。
基本上,空指针防止指针运算在派生到基础转换期间插入;你只会得到另一个空指针。该算术用于在这种转换期间固定非空指针,使得它指向适当的子对象。 offsetofclass
宏取决于此算法来确定偏移量。
数字 8
used是任意的。您可以使用 1
或 4
的任何数字,只要它不为零。 p>
ATL features a set of macros for so-called COM maps. COM map is a table that associates an interface GUID with an offset that is to be added to this
pointer to get to the corresponding subobject - the whole stuff works as replacement to explicit static_cast
for the upcast inside IUnknown::QueryInterface()
.
The map entries are built by using offsetofclass
macro:
#define _ATL_PACKING 8
#define offsetofclass(base, derived)\
((DWORD_PTR)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
which I'll rewrite as the following pseudocode "function" for readability in this question:
derived* derivedPointer = (derived*)_ATL_PACKING;
base* basePointer = static_cast<base*>(derivedPointer);
DWORD_PTR offset = (DWORD_PTR)(basePointer)-_ATL_PACKING;
Looks reasonable - it obtains a pointer to an imaginary derived object, then does an explicit static_cast
to shift the pointer, then computes distance between those imaginary objects.
The question is why is the constant 8 there? Why do we need that constant and why is it chosen to be 8?
The non-zero constant is there because the macro does not work with null pointers. We know that the value of a null pointer is a null pointer constant which evaluates to 0
:
C++ Standard 4.10/1 Pointer conversions [conv.ptr]:
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type....
This is the relevant clause with respect to converting from a derived class to a base class pointer type:
C++ Standard 4.10/3 Pointer conversions [conv.ptr]:
An rvalue of type "pointer to cv D," where D is a class type, can be converted to an rvalue of type "pointer to cv B," where B is a base class (clause 10) of D. If B is an inaccessible (clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion is a pointer to the base class sub-object of the derived class object. The null pointer value is converted to the null pointer value of the destination type.
Basically null pointers prevent pointer arithmetic from kicking in during a derived-to-base conversion; you will just get another null pointer. The arithmetic is used to "fix" non-null pointers during such conversions so that it points to the proper subobject. The offsetofclass
macro depends on this arithmetic to determine the offset.
The number 8
used is arbitrary. You could've used any number there like 1
or 4
, as long as it wasn't zero.
这篇关于当从对象的开始计算距离时,使用_ATL_PACKING常量是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!