可以将宏参数当成字符串。
#define TOSTRING(arg) (#arg)
printf("%s\n%s\n", TOSTRING(abc), TOSTRING(123));
结果:
abc
123
2. ##
可以将宏参数进行连接,但是最后产生一个C语言符号,而不是字符串。
#define CONNECTSTR(str1, str2) (final_string_##str1##_##str2)
CONNECTSTR(hello, world) 产生符号 final_string_hello_world
3. 宏展开
一般情况下,宏参数如果是一个宏的话,会首先将宏参数展开。
但是如果宏中有#或者##的话,就不会展开。
4. 调试宏
#define TOSTRING(arg) (#arg)
#define MACRO_DBG(arg) TOSTRING(arg)
#define ADD(a, b) ((a)+(b))
printf("%s\n", MACRO_DBG(ADD(1, 2)));
结果:
((1)+(2))
5.宏变参
宏定义同样可以接受可变参数个数的参数列表,为了向预处理器表明我们的宏接受可变参数,可以在参数列表后面跟上三个点(...),在随后的宏定义表达式中,我们使用特殊符号__VA_ARGS__来代表具体参数(注意,前后是双下划线),例如我们定义:
#define debugPrintf(...) printf("DEBUG: "__VA_ARGS__)
则可用下面方式使用该宏
debugPrintf("Hello world\n");
或者
debugPrintf("i= %d, j=%d \n",i,j);
输出分别为(加入i=100,j=200):
DEBUG: Hello World
DEBUG: i=100, j=200
#define yourerr(fmt, ...) \
printf("[%s][%s][%d]: ", __FILE__ ,__func__, __LINE__);\
printf(fmt, __VA_ARGS__)
6.得到指定地址上的一个字节或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
7.对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
8._ D AT E _宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
源代码翻译到目标代码的时间作为串包含在_ T I M E _中。串形式为时:分:秒。
9.#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
10. 如果串长于一行,可以在该行末尾用一反斜杠' \'续行。
11. #error 处理器命令 #error强迫编译程序停止编译,主要用于程序调试。
12.#pragma
其格式一般为: #pragma Para 其中para 为参数,下面来看一些常用的参数。
(1)message 参数 它能够在编译信息输出窗 口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: #Pragma message(“消息文本”)
#ifdef _X86
#Pragma message(“_X86 macro activated!”)
#endif
(2)另一个使用得比较多的pragma参数是code_seg。格式如:
#pragma code_seg( ["section-name"[,"section-class"] ] )
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。
(3)#pragma once (比较常用)
只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
(4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。
(5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。
(6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等价于:#pragma warning(disable:4507 34) // 不显示4507和34号警告信息
#pragma warning(once:4385) // 4385号警告信息仅报告一次
#pragma warning(error:164) // 把164号警告信息作为一个错误。
同时这个pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
这里n代表一个警告等级(1---4)。
#pragma warning( push )保存所有警告信息的现有的警告状态。
#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告
等级设定为n。
#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的
一切改动取消。例如:
#pragma warning( push )
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。
(7)pragma comment(...)
该指令将一个注释记录放入一个对象文件或可执行文件中。
常用的lib关键字,可以帮我们连入一个库文件。
(8)GNU C 支持两条`#pragma'指令使同一个头文档有两个用途:对象类的接口定义,对象类完整的内容定义.
#pragma interface