在C言语中宏界说是比较有用的技巧,在Linux源码中常常运用一些宏界说,比方宏container_of()等都是经典的宏界说表明办法。在C++不再建议运用宏界说,可是宏界说实际上却是是一个十分有用的手法。实质上宏界说可以搞定的完成选用其它的完成也是可以的,宏界说的效果是简略的代替效果,掌握这个是了解的要害,曾经在没有代码阅览量的时分总是认为宏界说便是简略的界说一些常量什么的,实质上否则,宏界说完全可以写成函数的办法,可是宏界说和函数有必定的不同,函数的调用一般选用栈的办法完成,这时分存在局部变量,形参、实参等问题,假如不了解C言语的实质,许多时分十分简单搞错,可是宏界说则否则,宏界说没有调用的进程,宏的完成仅仅是一个替换进程,不必压栈出栈,宏完成的相似函数修正的便是当时区域中的变量,不是局部变量。这也是一些较深层次的问题,在刚学习C言语的时分许多人只需看见相似于函数的办法都认为是函数,实质上不必定,很有或许便是选用宏界说完成的类函数,这时分就或许导致所谓的形参实参问题发生较大的改变。关于宏的问题在面试书面考试的进程中、写代码的进程中都是十分有用的部分,我就不再做介绍。
今日看了一遍博客《Reduce C-language coding errors with X macros》,感觉文章写得十分的好,也对自己写代码有了必定的协助,所以就将该文章用我自己的言语,写出来和咱们共享共享吧。
在嵌入式实时操作体系中,常常将体系分红许多层次,许多个模块,每一个模块都有自己的初始化进程,这时分咱们一般选用的办法如下所示:
typedef void(*p_func_t)(void);
enum
{
STATE_0,
STATE_1,
STATE_2,
…
STATE_M,
NUM_STATES
};
p_func_t inital_table[NUM_STATES]
{
func_0,
func_1,
func_2,
…
func_M,
};
这种完成办法是比较常见的完成办法,可是这种办法的缺陷是一切的初始化进程是依照必定的次序的,并且不能随机的初始化,因而假如在编码的进程中将状况号与初始化函数对应过错,将呈现比较难以发现的过错,这种过错常常呈现,当然有些编译器以及支撑随机的初始化进程,可是并不具有通用性,并且这种完成办法代码比较多,能不能选用宏界说的办法简化代码量呢?当然是可以的,选用相似于函数的宏界说就可以完成,详细的完成如下:
typedef void(*p_func_t)(void);
#define STATE_TABLE
ENTRY(STATE_0,func_0)
ENTRY(STATE_1,func_1)
ENTRY(STATE_2,func_2)
ENTRY(STATE_3,func_3)
ENTRY(STATE_4,func_4)
enum{
#define ENTRY(a,b) a,
STATE_TABLE
#undef ENTRY
NUM_STATES
};
p_func_t inital_table[NUM_STATES] =
{
#define ENTRY(a,b) b,
STATE_TABLE
#undef ENTRY
};
上面这种完成办法的长处是运用了宏界说简少代码量。我做一个扼要的剖析,首要选用宏界说界说了一组ENYRT,其间包括两个参数,分别是状况号STATE_N,和状况对应的初始化函数,这种完成办法可以防止上面所谓的状况号与函数对应过错的问题,由于在宏界说的进程中一般都会仔细的确认各种接口,对应好了只需求界说相关的函数就可以啦。在enum中选用了#define和#undef来限制这一组宏界说的效果规模,在个效果域中,ENTRY(a,b)是表明“a,”,需求留意不能疏忽a后的,由于这便是在enum中界说变量后要增加的符号,我想咱们应该知道enum{a,b,c,d}每一个成员后边都包括”,”的特性的。也便是说在这效果域中,ENTRY(a,b)被替换为”a,”,那么这时分STATE_TABLE就被替换为STATE_0,STATE_1等,然后和NUM_STATES就组成了第一个例程中的enum结构。而在p_func_t jumptable[NUM_STATES]依然选用了了STATE_TABLE,由于选用了#define和#undef限制了宏的效果规模,这时的ENTRY(a,b)将被代替为“b,”,也便是func_0,func_1等,这样也就完成了函数指针数组的初始化进程,这样的初始化可以削减状况号与初始化函数对应犯错的状况。
这样的完成也可以认为是宏界说的奇妙运用,可是这种办法仍是存在一些问题,由于选用#define 和#undef这种办法很或许导致过错的发生,由于很有或许不能很好的掌握这个限制效果域的运用办法,这时分可以选用一种新的相似函数的完成办法,可以让STATE_TABLE带一个参数,也便是选用相似指令的办法界说相关的内容:
typedef void(*p_func_t)(void);
/*以下发生几个常用的指令*/
/*enum发生*/
#define EXPAND_AS_ENUM(a,b) a,
/*初始化表发生*/
#define EXPAND_AS_INITTABLE(a,b) b,
/*声明各个函数*/
#define EXPAND_AS_FUNCDEC(a,b) void b(void);
/*将STATE_TABLE的参数便是详细的指令*/
#define STATE_TABLE(ENTRY)
ENTRY(STATE_0,func_0)
ENTRY(STATE_1,func_1)
ENTRY(STATE_2,func_2)
ENTRY(STATE_3,func_3)
ENTRY(STATE_4,func_4)
/*界说enum*/
enum{
STATE_TABLE(EXPAND_AS_ENUM)
NUM_STATES
};
/*声明各个函数*/
STATE_TABLE(EXPAND_AS_FUNCDEC)
/*初始化表*/
p_func_t inital_table[NUM_STATES] =
{
STATE_TABLE(EXPAND_AS_INITTABLE)
};
以上完成办法可以较好的防止#define和#undef的限制效果域问题,这实际上选用ENTRY作为参数传递给STATE_TABLE,然后ENTRY可用来完成不同的指令,这些指令的界说也是一系列的宏界说,这种完成架构可以比较好的防止短少声明等问题。一起也较少了过错的发生或许。