• 欢迎访问乐趣公园网站,WordPress信息,WordPress教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入乐趣公园 QQ群
  • Git主题现已支持滚动公告栏功能,兼容其他浏览器,看到的就是咯,在后台最新消息那里用li标签添加即可。
  • 最新版Git主题已支持说说碎语功能,可像添加文章一样直接添加说说,新建说说页面即可,最后重新保存固定连接,演示地址
  • 百度口碑求点赞啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊http://koubei.baidu.com/s/googlo.me
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏乐趣公园吧
  • 云落的淘宝店铺已经开张了哦,传送门:http://shop116317755.taobao.com

一些有用的宏

技巧心得 admin 45次浏览 0个评论

C++

利用宏来求结构体成员偏移值

 我们在书写C程序的时候,有时候需要根据结构体成员变量的地址,得到结构体的地址,特别是我们想用C来实现C++的继承特性的时候。

我们对问题的分析如下:

  • 输入:一个结构体定义type,这个结构体中某个成员变量的名字member以及它的地址ptr
  • 输出:包含此成员变量的结构体的地址

为了便于分析,我们给出一个实例来说明

struct father_t {
 *double c;
}f;
 *ptr = &(f.b);
而不是 ptr = f.b; 这里ptr是b的地址,而不是它指向的地址。
根据C语言对struct类型的存储特性,我们可以画这么一个图示:

通过分析图示,我们可以看出,我们只需要把当前知道的成员变量的地址ptr,减去它在结构体当中相对偏移4就的到了结构体的地址(ptr-4)。
在linux当中对此有一个很好的宏可以使用,叫做 container_of, 放在 linux/kernel.h(http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/

)当中。它的定义如下所示:

#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )

宏功能:获得一个结构体变量成员在此结构体中的偏移量。

1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;

3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址,即相对于0的偏移量,要的就这个;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型,size_t应该最终为unsigned int类型。
此宏的巧妙之处在于将 0 转换成(TYPE*),这样结构体中成员的地址即为在此结构体中的偏移量。

#include <stdio.h>

#define offsetof(TYPE, MEMBER) ((int)(&((TYPE *)0)->MEMBER))

struct _test_
{
 float main( temp = -;
 temp = offsetof(struct _test_, z);
 printf(temp = %d\n, temp);
 return
运行后结构为:temp = 8。

显然求出了 结构体成员变量 z 在结构体中的偏移量为 。
如果是

这个技巧在linux内核里面非常常见,通过常量 地址的强转得到一个数据类型

如果是char x,输出0;如果是y,输出4.

(int) 或(size_t)会怎么样?

编译不通过,无法将float *类型 转成float?
因为
&((TYPE *)0)->MEMBER) 得到的是一个指针,不能直接赋值给int 类型。
必须先用(int)强制转化下。

还有一个与这个有关的宏:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( ( *)__mptr - offsetof(type,member) );})

宏功能:从结构体(type)某成员变量(memberptr)来求出该结构体(type)的首指针。

对上面的定义,分析如下:

  1. (type *)0->member为设计一个type类型的结构体,起始地址为0,编译器将结构体的起始的地址加上此结构体成员变量的偏移得到此结构体成员变 量的偏移地址,由于结构体起始地址为0,所以此结构体成员变量的偏移地址就等于其成员变量在结构体内的距离结构体开始部分的偏移量。即:&((type *)0->member)就是取出其成员变量的偏移地址。而其等于其在结构体内的偏移量:即为:(size_t)(& ((type *)0)->member)经过size_t的强制类型转换后,其数值为结构体内的偏移量。该偏移量这里由offsetof()求出。
  2. typeof(((type *)0)->member)为取出member成员的变量类型。用其定义__mptr指针。ptr为指向该成员变量的指针。__mptr为member数据类型的常量指针,其指向ptr所指向的变量处。
  3. (char*)__mptr转换为字节型指针。(char*)__mptr – offsetof(type,member))用来求出结构体起始地址(为char *型指针),然后(type*)(char*)__mptr – offsetof(type,member))在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。

这就是从结构体某成员变量指针来求出该结构体的首指针。指针类型从结构体某成员变量类型转换为该结构体类型。

#include <stdio.h>

#define offsetof(TYPE, MEMBER) ((int)(&((TYPE *)0)->MEMBER))

#define container_of(ptr, type, member) ({   \
        const typeof( ((type *))->member ) *__mptr = (ptr); \
        (type *)( ( *)__mptr - offsetof(type,member) );})

struct _test_
{
  Assignment(struct _test_ *->x = ->y = ->z =  GetheadPoint( *struct _test_ * temp = -= container_of(tz,struct _test_, z);   根据成员变量的地址获得该结构体的首地址
 temp = p->y;                                       根据首地址获得其中另外一个成员变量的值

 printf(line31 = %d\n, temp);
}

 main( temp = -struct _test_ tmp;                            定义一个结构体变量

 Assignment(&tmp);                         给这个变量赋值
 GetheadPoint(&tmp.z);                   只传给这个函数一个结构体成员变量的地址

 printf(line43 tmp - >x = %d\n, tmp.x);
 
 return ;
}

运行结果为:

line31 = 
line43 tmp - >x =

2.计算数组长度(C/C++源程序)

#include <iostream>
using namespace std;

#define ARRAY_SIZE( ARRAY ) (sizeof (ARRAY) / sizeof (ARRAY[0]))

int main( void )
{
    int a[] = {1, 2, 3, 4, 5};
    cout << ARRAY_SIZE( a ) << endl;
 
    char b[] = "12345";
    cout << ARRAY_SIZE( b ) << endl;
    
    system( "PAUSE" );
    return EXIT_SUCCESS;
}

/*-------------------
5
6 (6是正确的哦,字符串的结束符也是一个元素)
请按任意键继续. . .
---------------------------------*/


★参考资料★ 
http://www.ok2002.com/cc/html/fcajsplv0qux131n-h7t9f48u-l0.e.2pnokzk_yrgb5h4c_gvx9rwjqmb6t5mae.html
转自:http://www.o-php.com/cc/h2tml/fcajsplv0qux131n-h7t9f48u-l0.e.2pnokzk_yrgb5h4c_gvx9rwjqmb6t5mae.html

乐趣公园 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明一些有用的宏
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址