CONTAINING_RECORD
来源:互联网 发布:ubuntu下安装jdk rpm 编辑:程序博客网 时间:2024/06/07 10:38
CONTAINING_RECORD 这样的一个宏,我看了它的定义,如下:
define CONTAINING_RECORD(address, type, field) ((type )( (PCHAR)(address) - (ULONG_PTR)(&((type)0)->field)))
class A
{
char c;
int a;
short b;
}
int a = 100;
int *pInt = &a;
比如,我调用了 CONTAINING_RECORD(pInt,A,a);
完全展开来后如下:
(A*)((char*)pInt - (unsigned long)(&((A*)0)->a))
为什么要用这个宏:
这个宏所做的操作其实就是把pInt与A结构中的相应的类型值进行一个位置配对。上面可以看到int a定义在第二个数据中,可以想象,如果我们有a的地址,然后直接把a转化成A*的话,很明显,a的地址就变成了A*的首地址了,但问题是A的第一个元素是char型的,这样的话,pInt就无法对齐上结构中的a元素的位置了。所以要进行一个偏移量操作.
下面,我们下解析一下:
首先,红色的部分很容易理解,我们知道,如果有一个int a;的指针,我们a - 1,其实相当于a - sizeof(int),相于于把指针向右移了4个位置,把一个指针转化成一个char型,这样,进行四则运算时就会按照我们正常的操作,(char*)(a - 1)就只是把指针移动了一个位置。
然后,看下紫色的部分,首先,要明白,对0指针的取值操作并不会出错,只是不确定这个值返回的是什么值,当然,如果我们对这个值进行修改,这是很危险的。这里用的0位置指针是很特别的,相对于0的位置,0指针对->a的操作,返回的数值取地址值后再转化成unsigned long值,其实得到的就是a相对于结构体A来说,偏移了多少个位置。0是起始地址,那么对于一个->操作,简单来理解,其实相当于0(结构体起始地址)+ sizeof(a前面的数据),当然,这里要考虑字节对齐的问题不过,编译器还是会帮我们把这些都完成。
最后,我们知道了pInt的结构体的首地址,知道了a的偏移地址,那么我们把pInt的地址值-偏移量,相当于把pInt倒退了偏移量个地址值,然后,我们再转换甩A*的话,相当于A*的起始地址已经是pInt的前面偏移量个地址,也就是a最前面的一个元素的地址值,对于A来说就是char c的地址,这样,我们就得到了正确的起始地址,然后再转换成(A*)的话,我们的pInt就能和A*的a的地址对应上了.
- CONTAINING_RECORD
- CONTAINING_RECORD
- CONTAINING_RECORD
- CONTAINING_RECORD
- CONTAINING_RECORD
- CONTAINING_RECORD
- CONTAINING_RECORD宏
- CONTAINING_RECORD宏
- CONTAINING_RECORD 宏
- 宏CONTAINING_RECORD
- CONTAINING_RECORD 宏
- CONTAINING_RECORD macro之研究
- CONTAINING_RECORD macro之研究
- CONTAINING_RECORD IN EFI
- CONTAINING_RECORD _CR 宏理解
- CONTAINING_RECORD宏的作用
- CONTAINING_RECORD macro之研究
- CONTAINING_RECORD IN EFI
- vlc-for-android
- python中的运算符
- Hadoop自定义分组Group
- Mybatis插入字段值乱码的解决方案
- 使用tar命令打包文件时,如何将符号链接文件替换为源文件
- CONTAINING_RECORD
- 正确加载 Javascript 和 CSS 到 WordPress
- hadoop Shell命令详解
- web.xml中classpath的理解
- killall -USR1&-HUP
- 重新认识UITabbleView
- HttpServletRequest与HttpServletResponse处理中文问题
- 修改Hosts文件
- Myeclipse 10 Mac字体模糊终极解决方案