文档章节

《C预处理》Linux内核中可变参数宏的用法

zhangyujsj
 zhangyujsj
发布于 2014/10/07 21:42
字数 1061
阅读 25
收藏 0

C语言预处理包括:宏定义、文件包含、条件编译等;预处理命令都以#开头:宏(#define)、文件包含(#include)、条件编译(#ifdef或#ifndef)。

本节主要分析宏定义的特殊用法。

一、#与##

1.#

#符号用作一个预处理运算符,它可以把语言符号转换成字符串。

eg:x是一个宏参数,那么#x可以把参数名转换成相应的字符串,这个过程叫字符串化。

test1.c

  1. #include <stdio.h>  
  2. #define PSQR(x) printf("the square of" #x "is %d.\n",(x)*(x))  
  3. int main(void)  
  4. {  
  5.     int y =4;  
  6.     PSQR(y);  
  7.     PSQR(2+4);  
  8.     return 0;  
  9. }  
  10.   
  11. /*result: 
  12. the square ofyis 16. 
  13. the square of2+4is 36. 
  14. */  
gcc test1.c -o test1

./test1

[plain] view plain copy
  1. the square ofyis 16.  
  2. the square of2+4is 36.  
2.##

该运算符把两个语言符号组合成单个语言符号。

test2.c

  1. #include <stdio.h>  
  2. #define XNAME(n) x##n  
  3. #define PXN(n) printf("x"#n" = %d\n",x##n)  
  4. int main(void)  
  5. {  
  6.     int XNAME(1)=12;//int x1=12;  
  7.     PXN(1);//printf("x1 = %d\n", x1);  
  8.     return 0;  
  9. }  
  10.   
  11. /*result: 
  12. x1 = 12 
  13. */  
gcc test2.c -o test2

./test2

[plain] view plain copy
  1. x1 = 12  
二、可变参数宏与__VA_ARGS__

__VA_ARGS__是一个可变参数宏,是新的C99规范中新增的,目前只有gcc支持(VC6.0的编译器不支持)。

宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏_ _VA_ARGS_ _就可以被用在替换部分中,替换省略号所代表的字符串。

简单例子:

test3.c

  1. #include <stdio.h>  
  2. #define PR(...) printf(__VA_ARGS__)  
  3. int main()  
  4. {  
  5.     int wt=1,sp=2;  
  6.     PR("hello\n");  
  7.     PR("weight = %d, shipping = %d\n",wt,sp);  
  8.     return 0;  
  9. }  
  10. /*result: 
  11. hello 
  12. weight = 1, shipping = 2 
  13. */  
gcc test3.c -o test3

./test3

[plain] view plain copy
  1. hello  
  2. weight = 1, shipping = 2  
三、在Linux内核系统调用中的应用

公共接口:

common.h(相当与内核中的systemcalls.h)

  1. #define __SC_DECL1(t1, a1)    t1 a1  
  2. #define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)  
  3. #define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)  
  4. #define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)  
  5. #define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)  
  6. #define __SYSCALL_DEFINEx(x, name, ...)                 \  
  7.      long sys##name(__SC_DECL##x(__VA_ARGS__))  
  8. #define SYSCALL_DEFINEx(x, sname, ...)              \  
  9.     __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)  
  10. #define SYSCALL_DEFINE0(name)      long sys_##name(void)  
  11. #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)  
  12. #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)  
1.无参数

test4.c

  1. #include <stdio.h>  
  2. #include "common.h"  
  3.   
  4. long sys_tank(void);  
  5. long sys_tankai(void);  
  6.   
  7. SYSCALL_DEFINE0(tank)  
  8. {  
  9.   printf("TK--------_>>>>>>tank call ok!!!\n");  
  10. }  
  11.   
  12. SYSCALL_DEFINE0(tankai)  
  13. {  
  14.   printf("TK--------_>>>>>>tankai call ok!!!\n");  
  15. }  
  16.   
  17. int main(){  
  18.   sys_tank();  
  19.   sys_tankai();  
  20.   return 0;  
  21. }  
  22.   
  23. /*result: 
  24. TK----->>>lianjie(a,b) is 20 
  25. TK----->>>lianjie(4,5) is 45 
  26. TK--------_>>>>>>tank call ok!!! 
  27. TK--------_>>>>>>tankai call ok!! 
  28. */  
gcc test4.c -o test4

./test4

[plain] view plain copy
  1. TK----->>>lianjie(a,b) is 20  
  2. TK----->>>lianjie(4,5) is 45  
  3. TK--------_>>>>>>tank call ok!!!  
  4. TK--------_>>>>>>tankai call ok!!  
2.一个参数

test5.c

  1. #include <stdio.h>  
  2. #include "common.h"  
  3.   
  4.   
  5. long sys_tank(int fd);  
  6.   
  7. SYSCALL_DEFINE1(tank, int, fd)  
  8. {  
  9.   printf("TK--------_>>>>>>call ok!!!>>fd is %d\n",fd);  
  10.   return 0;  
  11. }  
  12.   
  13. int main(){  
  14.   sys_tank(3);  
  15.   return 0;  
  16. }  
  17.   
  18.   
  19. /* 
  20. SYSCALL_DEFINE1(tank,int,fd) = SYSCALL_DEFINEx(1, _tank, int, fd) 
  21. SYSCALL_DEFINEx(1, _tank, int, fd) = __SYSCALL_DEFINEx(1, _tank, int, fd) 
  22. __SYSCALL_DEFINEx(1, _tank, int, fd) = long sys_tank(__SC_DECL1(int,fd)) 
  23. long sys_tank(__SC_DECL1(int,fd)) 
  24. //__SC_DECL1(int,fd) = int fd 
  25. //#define __SC_DECL1(t1, a1)    t1 a1 
  26. //#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__) 
  27. //#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__) 
  28. long sys_tank(__SC_DECL1(int,fd)) = long sys_tank(int fd); 
  29. */  
  30.   
  31. /*result: 
  32. TK--------_>>>>>>call ok!!!>>fd is 3 
  33. */  
gcc test5.c -o test5

./test5

[plain] view plain copy
  1. TK--------_>>>>>>call ok!!!>>fd is 3  
3.五个参数情况,其他不再罗列

test6.c

  1. #include <stdio.h>  
  2. #include "common.h"  
  3.   
  4. long sys_mount(char *dev_name, char *dir_name, char *type, unsigned long flags, void *data);  
  5.   
  6. SYSCALL_DEFINE5(mount, char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data)  
  7. {  
  8.   printf("TK--------_>>>>>>call ok!!!>>>dev_name is %s,dir_name is %s,flags is %d\n",dev_name,dir_name,flags);  
  9.   return 0;  
  10. }  
  11.   
  12. int main(){  
  13.   sys_mount(".""/", NULL, 0, NULL);  
  14.   return 0;  
  15. }  
  16.   
  17.   
  18. /* 
  19. SYSCALL_DEFINE5(mount,char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) = SYSCALL_DEFINEx(5, _mount, char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) 
  20. SYSCALL_DEFINEx(5, _mount, char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) = __SYSCALL_DEFINEx(5, _mount, char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) 
  21. __SYSCALL_DEFINEx(5, _mount, char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) = long sys_tank(__SC_DECL5(char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data)) 
  22. long sys_tank(__SC_DECL1(int,fd)) 
  23. //__SC_DECL5(char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) = char * dev_name, __SC_DECL4(char *, dir_name, char *, type, unsigned long, flags, void *, data) 
  24. //...... 
  25. //__SC_DECL5(char *, dev_name, char *, dir_name, char *, type, unsigned long, flags, void *, data) = char *dev_name, char *dir_name, char *type, unsigned long flags, void *data 
  26. //#define __SC_DECL1(t1, a1)    t1 a1 
  27. //#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__) 
  28. //#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__) 
  29. //#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__) 
  30. //#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__) 
  31. long sys_mount(__SC_DECL5(int,fd)) = long sys_mount(char *dev_name, char *dir_name, char *type, unsigned long flags, void *data); 
  32. */  
  33.   
  34.   
  35. /*result: 
  36. //TK--------_>>>>>>call ok!!!>>>dev_name is .,dir_name is /,flags is 0 
  37. */  
gcc test6.c -o test6

./test6

[plain] view plain copy
  1. TK--------_>>>>>>call ok!!!>>>dev_name is .,dir_name is /,flags is 0 



本文转载自:http://blog.csdn.net/tankai19880619/article/details/12015305

zhangyujsj
粉丝 24
博文 358
码字总数 224241
作品 0
广州
私信 提问
宏定义中的#,##,...,do{}while(0),__VA_ARGS__

宏定义中的#,## 1.在一个预处理器宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组 #define syslog(a) fprintf(stderr,"Warning: " #a"n"); 2.简单的说,“## ”是一种分隔连...

Linux_woniu
2017/09/20
0
0
盘点Linux内核源码中使用宏定义的若干技巧(1)

在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠或...

nothingfinal
2012/05/11
0
0
《Linux内核修炼之道》精华分享与讨论(7)——分析内核源码如何入手?(下)

下面的分析,米卢教练说了,内容不重要,重要的是态度。就像韩局长对待日记的态度那样,严谨而细致。 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB...

任桥伟
2010/03/08
0
0
C语言宏的特殊用法和几个坑 (转)

总结一下C语言中宏的一些特殊用法和几个容易踩的坑。由于本文主要参考GCC文档,某些细节(如宏参数中的空格是否处理之类)在别的编译器可能有细微差别,请参考相应文档。 宏基础 宏仅仅是在C...

shzwork
03/14
12
0
内核工具 – Sparse 简介

sparse介绍 Sparse 诞生于 2004 年, 是由linux之父开发的, 目的就是提供一个静态检查代码的工具, 从而减少linux内核的隐患. 其实在Sparse之前, 已经有了一个不错的代码静态检查工具("SWAT"),...

面码
2014/08/17
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

JDBC+C3P0+DBCP 基本使用

1.概述 这篇文章主要说了JDBC的基本使用,包括Statement,PreparedStatement,JDBC的连接,Mysql创建用户创建数据表,C3P0的连接与配置,DBCP的连接与配置. 2.mysql的处理 这里的JDBC使用Mysql作为...

Blueeeeeee
39分钟前
3
0
MVC Linux下开发及部署

linux使用的是 Ubuntu 64 位 18.04.2 LTS 首先复制C:\Program Files (x86)\Embarcadero\Studio\20.0\PAServer 下 LinuxPAServer20.0.tar.gz 到 linux 目录下 运行链接编译程序 delphi环境配置......

苏兴迎
今天
9
0
3.控件及其属性

1.文本 2.按钮

横着走的螃蟹
今天
7
0
安装Genymotion模拟器慢的解决方案

第一步点击下载, C:\Users\Administrator\AppData\Local\Genymobile\genymotion.log 中搜索 ova 会发现这个文件 使用迅雷下载即可. 在 虚拟机中导入这个.ova 文件 即可安装...

chenhongjiang
今天
5
0
4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了)

你好,我是彤哥,本篇是netty系列的第四篇。 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识。 简介 上一章我们一起学习了Java中的BIO/NIO/AIO的故事,本章将带着大家一起使用纯纯的N...

彤哥读源码
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部