免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8854 | 回复: 12
打印 上一主题 下一主题

关于一个宏定义引出的c语法思考 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-19 12:53 |只看该作者 |倒序浏览
这个宏定义,功能我知道,但就是它的语法格式和C的感觉有点不同(难道是GUN c的规范?),有谁懂的给讲解一下,谢谢
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})

在使用这个宏的时候,我们用x=container_of(p,u,v),问题就出来了,因为宏定义室完全的替换,那不是换成x={……;ptr-offset();}了,赋值语句好像没有这种=号后面跟大括号,然后里面还可以分号隔开的语句吧,感觉就像这种赋值语句a={(int)x;x-y;}(这种语法至少VC编译通不过),那请问这是gun c的语法吗,还是我对宏的理解有偏差?
  谢谢!

[ 本帖最后由 hijohnny 于 2007-12-19 13:25 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-12-19 13:33 |只看该作者
原帖由 hijohnny 于 2007-12-19 12:53 发表
这个宏定义,功能我知道,但就是它的语法格式和C的感觉有点不同(难道是GUN c的规范?),有谁懂的给讲解一下,谢谢
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__m ...


这是GCC的扩展
在GNU中, 通过在一个复合语句外加一对圆括号, 可以产生一个返回值. 如下面的表达式就返回8:

  1. ret = ({
  2.                 int a = 5;
  3.                 int b;
  4.                 b = a + 3;
  5.       });
复制代码

返回的值就是语句块中的最后一个语句的返回值.
这种结构在写宏的时候很有用. 比如

  1. #define even(x) (2*(x/2) == x ? x : x + 1)
复制代码

这是对x取整的. 如果在调用时使用even(i++)这种方式的话, 则会得出错误的结果.
但是如果使用下面的方法:

  1. #define even(x)\
  2. ({\
  3.         int y = x;\
  4.         (2*(y/2) == y ? y:y+1);\
  5. })
复制代码

这样的话, 使用even(i++)也可以得到正确的结果.

评分

参与人数 1可用积分 +9 收起 理由
sakulagi + 9 我很赞同

查看全部评分

论坛徽章:
0
3 [报告]
发表于 2007-12-19 13:51 |只看该作者
恩,明白了~~非常感谢scutan ,不过我经常看到大家说gnu的c语法扩展,也在很多书上零星的看到过一些GNU C语法的内容,但不知道哪里有完整的GNU C语法扩展可以参看学习一下呢~谢谢

论坛徽章:
0
4 [报告]
发表于 2007-12-19 14:01 |只看该作者

回复 #3 hijohnny 的帖子

http://linux.chinaunix.net/bbs/v ... mp;highlight=scutan

你看看这本书, 就是讲gcc的.

论坛徽章:
0
5 [报告]
发表于 2007-12-19 14:46 |只看该作者
o,非常感谢,

论坛徽章:
0
6 [报告]
发表于 2007-12-19 23:52 |只看该作者
请问这种定义中的临时变量有什么意义呢?为什么不直接用ptr的值直接减去偏移量的值?

  1. const typeof( ((type *)0)->member ) *__mptr = (ptr);        \
复制代码

论坛徽章:
0
7 [报告]
发表于 2007-12-19 23:57 |只看该作者
明白了,多了类型检查

论坛徽章:
0
8 [报告]
发表于 2007-12-27 14:31 |只看该作者
又学习了一招
谢谢了

论坛徽章:
0
9 [报告]
发表于 2009-11-28 22:08 |只看该作者
有谁能回答一下这个问题么?
我也不明白,搜到这里来了

原帖由 wiseker 于 2007-12-19 23:52 发表
请问这种定义中的临时变量有什么意义呢?为什么不直接用ptr的值直接减去偏移量的值?

const typeof( ((type *)0)->member ) *__mptr = (ptr);        \

论坛徽章:
0
10 [报告]
发表于 2009-11-28 22:11 |只看该作者

回复 #6 wiseker 的帖子

刚刚从别的地方找到答案了,供后人参考,如下:

这个宏是由两个语句组成,最后container_of返回的结果就是第二个表达式的值。这里__mptr为中间变量,这就是list_head指针类型,它被初始化为ptr的值,而ptr就是当前所求的结构体中list_head节点的地址。为什么要用中间变量,这是考虑到安全性因素,如果传进来一个ptr++,所有ptr++放在一个表达式中会有副作用,像 (p++)+(p++)之类。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP