> #define STRCPY(dst, src) strcpy(dst, #src)
则
> STRCPY(buff, abc) 相当于 strcpy(buff, "abc")
##符号:“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接[##前后的有无空格一样的效果],是一个连接符号将参数连接在一起
#define A1(name, type) type name_##type##_type [type,name_,type,_type,被分成四段,type和name前面出现过被替换,而name_,_type不会被替换]
A1(a1, int); /* 等价于: int name_int_type; */
#define A2(name, type) type name ## _ ## type ## _type[type,name,_,type,_type]
A2(a1, int); /* 等价于: int a1_int_type; */
#define FOO(str) my##str
FOO(abc) ==> myabc [也可以理解为##阻止了#的字符串化]
凡是宏定义里面有用#或##的地方宏参数是不会再展开的
##__VA_ARGS__:这是一个可变长度参数的宏定义,而前面的##作用是为了防止0个参数的时候去掉前面的,作用,以免编译出错
#@符号:将宏参数变成一个字符[即加上一个单引号‘’#@与参数之间可以有空格]
#define FOO(a) #@a
FOO(a) ==> 'a'
#define function() (void(0)) 防止此函数作为右值
#define FSIZ( type, field ) sizeof( ((type *) 0)->field ) //获取结构体中field类型的大小
此处的0只是作为一个临时的指针地址用,任何可以表示地址的数字都可以代替0
type为结构体类型:
a = (type* 0): a=0
a = (int)&(type* 0)->field a = field在结构体中偏移大小[字节]
(type*)0;就是假设地址0处存放的是一个type类型的结构体变量
这样的话这个结构体变量的基址就是0,所以结构体成员变量的地址的大小在数值上就等于该结构体成员在结构体中的偏移量
0就看作一个地址,那么 (type *0) 就是将从地址0开始的一段内存转化为一个type类型的指针
typeof[__typeof__]的作用:用于获取表达式的数据类型,参数可以是表达式或者数据类型,如果表达式是函数,则只返回函数的返回值类型但是不执行此函数
1,把y定义成x指向的数据类型: typeof(*x) y;
2,把y定义成x指向数据类型的数组: typeof(*x) y[4];
3,把y定义成一个字符指针数组: typeof(typeof(char *)[4] y; ===》char *y[4];
4,把y定义成一个int型指针: typeof(int *)x,y;======>int *x,*y;
我们再换一种定义方式:
#define pointer(T) typeof(T *)
#define array(T,N) typeof(T [N])
array (pointer(char),4) y; ======>char *y[4]
#define likely(x) __builtin_expect(!!(x), 1) 【只有在GNU平台下面才有这个 (!!)只是为了将传进来的数值转变成bool值】
#define unlikely(x) __builtin_expect(!!(x), 0)
__buildin_expect((x), 1)表示x的值为真的可能性更大.
__buildin_expect((x), 0)表示x的值为假的可能性更大.
也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种方式,编译器在编译过程中,会将可能性更大的代
码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降
[总之,likely和unlikely的功能就是添加 cache的命中率,提高系统执行速度
比如 :
if (likely(a>b)) {
fun1();
}
if (unlikely(a fun2();
}
这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数的二进制代码紧跟在前面程序的后面,这样就
cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。这样,也就添加了cache的命中率
C语言中的逗号运算符只能用来连接表达式,不能用来连接语句
如果一个宏包含的是一系列的语句,并且宏定义中使用以下模式
do{
。。。。
。。。。
}while(0)
是为来在宏替换的时候不会多出最后一个语句的;符号,因为do{}while(0)模式后面总是需要跟着一个;符号的
#define ECHO(s) \
do{ \
gets (s) ; \
puts (s) ; \
} while (0)
当使用ECHO宏时,一定要加分号:
ECHO(str);
宏定义的“空操作”
#define DEBUG
#ifdef DEBUG
只是为来保持一致性
如果宏定义里面有return,那么执行完这个宏,调用此宏的函数就会返回而不会执行下面的语句
与平台相关的宏
#if define(SYS_thread_selfid)
ownerid = syscall(SYS_thread_selfid);
#elif defined(SYS_gettid)
ownerid = syscall(SYS_gettid);
#endif