1. 宏可以像函数一样被定义
#define min(x,y) ((x) <(y)?(x):(y)) 但是在实际使用时,只有当写上min(),必须加括号,min才会被作为宏展开,否则不做任何处理,参数必须加括号,防止展开错误。
2.#和##
#符号把一个符号直接转换为字符串,
#define ToSTRING(x) #x
const char *str = ToSTRING( test_string ); str的内容就是"test_string",也就是说#会把其后的符号直接加上双引号。
##符号会连接两个符号,从而产生新的符号(词法层次),这可以利用一个符号前缀生成更多的不通后缀的符号或变量。
#define SIGN( x ) INT_##x
int SIGN( 1 ); 宏被展开后将成为:int INT_1;
3.变参宏,你可以定义类似的宏:
#define LOG( format, ... ) printf( format, __VA_ARGS__ )
LOG( "%s %d", str, count );
__VA_ARGS__是系统预定义宏,被自动替换为参数列表
4.宏的模版功能,可以利用宏和##产生不通类型声明和成员变量拓展,这样运行CREATE函数之后,我们就生成了一个enum类型,里面的成员就可以使用了,在bit field的时候很有用。
#define CREATE(base, pianyi, daxiao) \
enum{
base ## shift = pianyi,
base ## size = daxiao
}
5.小技巧
取结构体成员偏移:
#define offset(t,m) (uint_8)(&(((t*)0)->m))
根据某个结构题的某个成员变量取整个结构题变量的首地址:
#define GET_STRUCT_FROM_OFFSET(member_ptr, type,member) (type *)((char *)(member_ptr) - offsetof(type,member))
计算数组大小:
#define ARRAY_SIZE(arr) sizeof(arr)/sizeof(arr[0])
未完待续。。。。。。