宏定义之二(连接符,可变參数,文件名称,行号,函数名)

宏的高级使用--##,__VA_ARGS__, __FILE__, __FUNCTION__等

转自 http://blog.csdn.net/yiya1989/article/details/7849588

先说一下本文中会提到的内容:##,__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__等

宏变量:

先举一个样例,会用到上面这些宏:

[cpp] view
plain
copy

  1. #define myprintf(...) printk("[lch]:File:%s, Line:%d, Function:%s," \
  2. __VA_ARGS__, __FILE__, __LINE__ ,__FUNCTION__);

此处的 #define 的作用是将 myprintf( )换成后面那一大串的内容,而括号内 ... 的内容原样抄写在 __VA_ARGS__ 的位置。终于输出例如以下:

[lch]:File:arch/arm/mach-omap2/board-omap3wscec-camera.c, Line:163, Function:beagle_cam_init,camera init!

解析:

1)__VA_ARGS__:整体来说就是将左边宏中 ... 的内容原样抄写在右边 __VA_ARGS__ 所在的位置。它是一个可变參数的宏,是新的C99规范中新增的,眼下似乎仅仅有gcc支持(VC从VC2005開始支持)。要注意的是,printf 的输出格式是括号内左边是字符串,右边是变量,并且右变量与左输出格式是一一相应的。所以在上面那个样例中, __VA_ARGS__仅仅能是一些不含不论什么变量的字符串常量。由于上面的样例中若__VA_ARGS__含有变量,整个printf的输出与变量便不能一一相应,输出会出错。

假设不过替换函数名,可用例如以下方式,此时对__VA_ARGS__无不论什么特殊要求:#define myprintf(...) printk( __VA_ARGS__),在调试程序时能够这样用:

[cpp] view
plain
copy

  1. #ifndef LOG_NDEBUG_FUNCTION
  2. #define LOGFUNC(...) ((void)0)
  3. #else
  4. #define LOGFUNC(...) (printk(__VA_ARGS__))
  5. #endif

2) __FILE__ :宏在预编译时会替换成当前的源文件名称

3) __LINE__:宏在预编译时会替换成当前的行号

4) __FUNCTION__:宏在预编译时会替换成当前的函数名称

5)类似的宏还有 __TIME__,__STDC__, __TIMESTAMP__等,就全然当一个变量来使用就可以。

宏连接符##:

举个样例:宏定义为#define XNAME(n) x##n,代码为:XNAME(4),则在预编译时,宏发现XNAME(4)与XNAME(n)匹配,则令 n 为 4,然后将右边的n的内容也变为4,然后将整个XNAME(4)替换为 x##n,亦即 x4,故 终于结果为 XNAME(4) 变为 x4.

代码例如以下:

[cpp] view
plain
copy

  1. #include <stdio.h>
  2. #define XNAME(n) x ## n
  3. #define PRINT_XN(n) printf("x" #n " = %d/n", x ## n);
  4. int main(void)
  5. {
  6. int XNAME(1) = 14; // becomes int x1 = 14;
  7. int XNAME(2) = 20; // becomes int x2 = 20;
  8. PRINT_XN(1); // becomes printf("x1 = %d,", x1);
  9. PRINT_XN(2); // becomes printf("x2 = %d/n", x2);
  10. return 0;
  11. }

输出为:x1 = 14, x2 = 20

PS:编译过程:

1,扫描解析文件

2,预处理(宏在此时处理,该替换的文字会被替换)

3,对处理过的源码进行汇编,输出汇编语言的代码(C语言的控制流程被处理)

4,编译为二进制目标文件

5,与程序库进行链接,输出终于的程序文件

(宏 和 C语言在不同的阶段处理运行)

时间: 2024-11-06 10:54:07

宏定义之二(连接符,可变參数,文件名称,行号,函数名)的相关文章

C宏定义中的连接符&quot;##&quot;和字符串化操作符&quot;# &quot;及变参宏&quot;...&quot;

C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念). 1.宏定义中字符串化操作符#: #的功能是将其后面的宏参数进行字符串化操作,意思就是对它所应用的宏变量通过替换后在其左右各加上一个双引号. 例如: #define WARN_IF(EXPR)do { if (EXPR) fprintf(stderr, "Warning: " #EXPR "\n");} while(0) 上面代码中的反斜线\主要用来转译换行

C/C++ 打印源文件名和行号函数名的宏

__FILE__             宏在预编译时会替换成当前的源文件名__LINE__             宏在预编译时会替换成当前的行号 __FUNCTION__   宏在预编译时会替换成当前的函数名称

可变參数列表

再c++里有函数重载.在c里有可变參数列表,用stdarg宏实现定义在<stdarg.h>的头文件里,当中有3个宏:va_start(va_list的变量名,省略号前最后一个有名字的參数)用于初始化,va_arg(va_list的变量名,可变參数类型)用于取出可变參数.va_end(va_list的变量名)用于表明结束取值.用va_list声明一个类型为va_list的变量如arg #include<stdio.h> #include<stdarg.h> float a

C语言利用va_list、va_start、va_end、va_arg宏定义可变參数的函数

在定义可变參数的函数之前,先来理解一下函数參数的传递原理: 1.函数參数是以栈这样的数据结构来存取的,在函数參数列表中,从右至左依次入栈. 2.參数的内存存放格式:參数的内存地址存放在内存的堆栈段中,在运行函数的时候,从最后一个(最右边)參数開始入栈.因此栈底高地址,栈顶低地址,举个样例说明一下: void test(int a, float b, char c); 那么,在调用test函数的时候,实參char c先进栈,然后是float b,最后才是int a,因此在内存中变量的存放次序是c-

C在宏定义中使用的语言可变参数

于C标准库的语言,printf.scanf.sscanf.sprintf.sscanf入输出函数,參数都是可变的.在调试程序时.我们可能希望定义一个參数可变的输出函数来记录日志,那么用可变參数的宏是一个不错的选择. 在C99中规定宏也能够像函数一样带可变的參数,如: #define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__) 当中,...表示可变參数列表,__VA_ARGS__在预处理中,会被实际的參数集(实參列表)所替换. 同一时

可变參数学习笔记

一.什么是可变參数 我们在C语言编程中有时会遇到一些參数个数可变的函数,比如printf()函数,其函数原型为: int printf( const char* format, ...); 它除了有一个參数format固定以外,后面跟的參数的个数和类型是可变的(用三个点"-"做參数占位符),实际调用时能够有下面的形式: printf("%d",i); printf("%s",s); printf("the number is %d ,s

c 语言函数可变參数的处理

/************************************************************************* > File Name: va_list.c > Author: zshh0604 > Mail: [email protected] > Created Time: 2014年10月14日 星期二 15时16分09秒 **********************************************************

可变參数

C++中传递參数时,有时候不确定參数的数量,这时候能够使用可变參数.例如以下: 1.std::initializer_list C++11标准,使用方法类似vector,參数类型需同样.使用方法例如以下: #include <initializer_list> void  method(std::initializer_list<int> il) { for(auto i: il) { printf("%d", i) ; } } int _tmain(int a

iOS 处理方法中的可变參数

## iOS 处理方法中的可变參数 近期写了一个自己定义的对话框的demo,想模仿系统的UIAlertView的实现方式.对处理可变參数的时候,遇到了小问题,于是谷歌了一下.写下了处理问题的方法.记录下来,以备后需. 代码实现 - (instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelBu