当从对象的开始计算距离时,使用_ATL_PACKING常量是什么? [英] What's the use of _ATL_PACKING constant when computing distance from the start of object?

查看:112
本文介绍了当从对象的开始计算距离时,使用_ATL_PACKING常量是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆