盘点Linux内核源码中使用宏定义的若干技巧(1)

转载 2012年03月22日 16:52:38

在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发:

1. 类型检查
比如module_init的宏定义:
<include/linux/init.h>

点击(此处)折叠或打开

  1. #define module_init(initfn)                    \
  2.     static inline initcall_t __inittest(void)        \
  3.     { return initfn; }                    \
  4.     int init_module(void) __attribute__((alias(#initfn)));
module_init宏的关键点是在代码中的第4行,通过gcc别名的特性将init_module与initfn等同起来。这里宏定义的技巧出现在第2和3行,通过return initfn实际上是来对initfn做静态类型检查,以确保程序员不会提供一个原型不符合要求的模块初始化函数,后者要求是一个参数值为void,返回者为int类型的函数。所以,如果你定义了一个比如void my_module_init(void)或者是void my_module_init(int)这样的模块初始化函数作为module_init宏参数,那么编译时就会出现类似下面的warning:
GPIO/fsl-gpio.c: In function '__inittest':
GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

2. 变长参数列表,比如系统调用相关的定义:
<include/linux/syscalls.h>

点击(此处)折叠或打开

  1. #define __SYSCALL_DEFINEx(x, name, ...)                    \
  2.     asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

点击(此处)折叠或打开

  1. #define SYSCALL_DEFINEx(x, sname, ...)                \
  2.     __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

点击(此处)折叠或打开

  1. #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
  2. #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
  3. #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
  4. #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
  5. #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
  6. #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
所以源码中的SYSCALL_DEFINE1(close, unsigned int, fd)将展开成:
asmlinkage long sys_close(__SC_DECL1(unsigned int, fd))
可见,上述宏定义SYSCALL_DEFINE1中除第一个参数明确给出外,对于可变长的参数列表,采用__VA_ARGS__就可以圆满解决,换言之,__VA_ARGS__成了变长参数列表的容器了。

3.这条也不能算是技巧了,C中宏定义的一种很常见的用法,Linux内核源码中也大量使用:
  #define STR(x)  #x
#的使用将把宏参数x变成一个字符串,比如STR(my hub)将转化成"my hub"
另一个常见的符号是##,它用来将两个参数粘合到一起,比如
  #define STR1(a,b) a##b
那么STR1(my hub,   is good)将转换成my hubis good,可见##会自动把第2个参数前的空格给移除掉。

4. do...while(0)这个就不用多说了吧,不过有个问题是,如果使用{...}来代替do{...)while(0)行不行呢?

linux内核源码中常见宏定义

1. gcc的__attribute__编绎属性要了解Linux Kernel代码的分段信息,需要了解一下gcc的__attribute__的编绎属性,__attribute__主要用于改变所声明或定...
  • yangdelong
  • yangdelong
  • 2010年04月20日 18:25
  • 2816

盘点Linux内核源码中使用宏定义的若干技巧

盘点Linux内核源码中使用宏定义的若干技巧(1) 2012-07-24 09:50:38 分类: 原文地址:盘点Linux内核源码中使用宏定义的若干技巧(1) 作者:MagicBo...
  • cosmoslhf
  • cosmoslhf
  • 2013年12月12日 16:11
  • 720

盘点Linux内核源码中使用宏定义的若干技巧(2)

5. typeof和0指针这个在大名鼎鼎的container_of就有出现,事实上一些面试题有时候也喜欢跟这个沾点边。 点击(此处)折叠或打开#define offsetof(TYPE, MEMBER...
  • qizheguang
  • qizheguang
  • 2016年01月21日 09:26
  • 94

Linux内核源码中使用宏定义的若干技巧

在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: ...
  • sdulibh
  • sdulibh
  • 2016年04月19日 15:05
  • 593

浅谈宏定义使用技巧

1、宏定义介绍          宏定义又称为宏替换,简称宏。它是在预处理阶段用预先定义的字符串替代标识符的过程。其定义的一般形式为:  #define    标识符    字符串       ...
  • jsh13417
  • jsh13417
  • 2013年03月17日 17:44
  • 2992

linux 内核源码 系统调用宏定义

linux 内核源码中关于系统调用源码阅读
  • yueyingshaqiu01
  • yueyingshaqiu01
  • 2015年09月28日 17:07
  • 585

linux内核源码的技巧

http://blog.csdn.net/njufeng/article/details/29902287 看内核代码时,有些语言成分或者说编程技巧平常没见过更没用过,这里先记下一些: ...
  • fzs333
  • fzs333
  • 2015年06月09日 15:04
  • 425

仓库盘点的四大方法和盘点流程

仓库盘点的四大方法提要:一般仓库都要定期盘点,好一点的仓库,每一周盘一次,也有每个月盘点的,也有每个季度或年末盘点的,每一年至少盘一次。文 章来源于 www.fdcew.COM   盘点的四大方...
  • boonya
  • boonya
  • 2016年07月12日 11:44
  • 13315

Linux内核源码--min,swap宏定义

Linux3.5的部分宏定义在Linux-3.5/include/linux/kernel.h的头文件中有定义 一: 最大值和最小值相关的宏 [cpp] view ...
  • ly890700
  • ly890700
  • 2017年06月24日 23:14
  • 202

Linux内核源码中两个宏定义likely,unlikely

#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) 由于刚开始...
  • zaizai09
  • zaizai09
  • 2013年09月27日 21:01
  • 778
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:盘点Linux内核源码中使用宏定义的若干技巧(1)
举报原因:
原因补充:

(最多只允许输入30个字)