预处理命令
#define,#error,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。非常明显,所有预处理命令均以符号#开头
#line用于重置由__LINE__和__FILE__宏指定的行号和文件名。
#error指令使预处理器发出一条错误消息,该消息包含指令中的文本.这条指令的目的就是在程序崩溃之前能够给出一定的信息。
#pragma的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
C++宏体中出现的#,#@,##
宏体中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变量。比如你要做一个菜单项命令名和函数指针组成的结构体
宏定义命令
#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。
(1) 简单的宏定义:
#define <宏名> <字符串>
例: #define PI 3.1415926
(2) 带参数的宏定义
#define <宏名> (<参数表>)<宏体>
在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。
宏定义用法
#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x
- #define Conn(x,y) x##y :表示x连接y,举例说:
int n = Conn(123,456); 结果就是n=123456;
- #define ToChar(x) #@x:表示给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);结果就是a='1';
做个越界试验char a = ToChar(123);结果是a='3';
- #define ToString(x) #x :表示给x加双引号
char* str = ToString(123132);就成了str="123132";
预定义宏
在标准C以及各中编译器中定义了一些对象宏, 这些宏的名称以"__"开头和结尾, 并且都是大写字符. 这些预定义宏可以被#undef, 也可以被重定义。
概括起来GCC中可使用的预定义宏涵盖了如下几方面的信息:
1、宿主的信息:GNU的版本,编译器的版本,类型的相关信息,字节序信息等。
2、编译动作的信息:编译的日期、时间;编译时是否进行了时间或空间上的优化;定义的inline是否被编译器执行等。
3、文件的信息:文件名称、函数名称、行数信息、文件最后修改时间等等。
4、计数信息:__COUNTER__,__INCLUDE_LEVEL__等。
1、__FILE__ 代表当前源代码文件名的字符串文字 ,包含了详细路径,如G:/program/study/c+/test1.c
__LINE__ 代表当前源代码中的行号的整数常量
__func__ 当前所在函数名,在编译器的较高版本中支持
__FUNCTION__ 当前所在函数名
3、__DATE__,__TIME__
__DATE__ 进行预处理的日期(“Mmm dd yyyy”形式的字符串文字,如May 27 2006)
__TIME__ 源文件编译时间,格式微“hh:mm:ss”,如:09:11:10;
4、__TIMESTAMP__
5、__GNUC__、__GNUC_MINOR__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__
用于得到GNU版本:
6、__VERSION__
用于得到编译器的版本
7、__COUNTER__
自身计数器,用于记录以前编译过程中出现的__COUNTER__的次数,从0开始计数。常用于构造一系列的变量名称,函数名称等。
8、__INCLUDE_LEVEL__
用于表示文件被包含的计数,从0开始递增,常作为递归包含的限制条件。
9、__PRETTY_FUNCTION__ 非标准宏。这个宏比__FUNCTION__功能更强:
1)若用g++编译C++程序, __FUNCTION__只能输出类的成员函数名,不会输出类名;而__PRETTY_FUNCTION__则会以 <return-type> <class-name>::<member-function-name>(<parameters-list>) 的格式输出成员函数的详悉信息(注: 只会输出parameters-list的形参类型, 而不会输出形参名).
2)若用gcc编译C程序,__PRETTY_FUNCTION__跟__FUNCTION__的功能相同.
BOOST宏
#define MACRO x123
#define RES MACRO##yy
//RES结果是MACROyy,而我们希望的是x123yy,这样,把RES 改为
#define RES BOOST_PP_CAT(MACRO,yy)
#define B 1
#define C1 BOOST_PP_CAT(A, B)
#define C2 BOOST_PP_CAT_SIMPLE(A, B)
//C1是A1,而C2是AB。也就是说:
//如果B不是宏,BOOST_PP_CAT和BOOST_PP_CAT_SIMPLE没有区别;
//如果B是宏,BOOST_PP_CAT_SIMPLE依然是直接连接,而BOOST_PP_CAT宏是先将B宏展开,然后连接。
BOOST_PP_SEQ_FOR_EACH宏,用于将一个序列中参数依次按照指定宏进行展开。
BOOST_PP_SEQ_FOR_EACH(macro, data, seq)
BOOST_PP_SEQ_FOR_EACH是一个重复项的宏。
如果序列是(a)(b)(c),则展开为:
macro(r, data, a) macro(r, data, b) macro(r, data, c)
如果要求更高效率,可使用BOOST_PP_SEQ_FOR_EACH_R
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define SEQ (w)(x)(y)(z)
#define MACRO(r, data, elem) elem::GetInstance()
BOOST_PP_SEQ_FOR_EACH(MACRO, _, SEQ)
// expands to w::GetInstance() x::GetInstance() y::GetInstance() z::GetInstance()
BOOST_PP_EXPR_IIF