C语言宏的使用小结

来源:互联网 发布:java 构造函数返回值 编辑:程序博客网 时间:2024/05/18 22:54

1.防止一个头文件被重复包含

#ifndef __HEAD_H_#define __HEAD_H_#include <stdio.h>......#endif

2.得到指定地址上的一个字节或字

#define MEM_BYTE(x)  (*((char *)(x)))#define MEM_WORD(x)  (*((short *)(x)))

3. 得到一个field在结构体(struct)中的偏移量

#define GET_OFFSET_STRUCT(type,field)       (&(((type *)0)->field))

说明:
这里涉及到结构体中成员边界对齐的问题,相同的结构体在不同的CPU和编译器上会得到不同的结果。

如下面的代码,所得到的偏移是不同的。
测试的环境是:

  • MacBookPro OS 10.12.3 + MacOS gcc.
  • sizeof(char)=1,sizeof(short)=2,sizeof(int)=4,sizeof(long)=8,sizeof(float)=4
  • sizeof(struct Student)=40=4+4+8+4+4*5
  • sizeof(struct StudentPacked)=37=1+4+8+4+4*5
struct Student {    char a; //offset=0    int b; //4    long c; //8    float d; //16    int e[5]; //20};struct StudentPacked {    char a; //offset=0    int b; //1    long c; //5    float d; //13    int e[5]; //17}__attribute__((packed));

4.得到一个结构体中field所占用的字节数

#define GET_FIELD_SIZE(type,field)      (sizeof(((type *)0)->field))

5.返回数组元素的个数

#define ARRAY_SIZE(a)       (sizeof((a)) / sizeof((a[0])))

6.使用__LINE__等宏输出日志

printf("%s %s %d %s %s\n",__FILE__,__FUNCTION__,__LINE__,__DATE__,__TIME__);

输出结果为: ../src/UsefulC.c main 58 Feb 23 2017 01:55:08

7.宏定义中#,##的用法

#表示把宏定义中的参数转化为字符串, ##表示把宏定义中的参数连接起来,看实例:

#define STR(s)     #s#define CONS(a,b)  ((int)(a##e##b))printf(STR(vck)); // 输出"vck"printf("%d\n", CONS(2,3)); // 输出2000,即2e3=2*10^2

注意:
上面STR和CONS的参数是不能加括号的,就是说不能这样定义:
#define STR(s) #(s)
#define CONS(a,b) ((int)((a)##e##(b)))

深入一点,当宏参数是另一个宏的情况下,宏参数是不会展开的,是不是不知所云,举一个例子,

#define A   2#define STR(s)     #s#define CONS(a,b)  ((int)(a##e##b))printf(STR(A)); // 输出"A"printf("%d\n", CONS(A,A)); //CONS(A,A)被替换为AeA,编译出错了

如何避免这个错误呢,很简单,在加一个转换宏即可,代码如下,

#define A  2#define STR(s)  _STR(s)#define CONS(a,b)   _CONS(a,b)#define _STR(s)     #s#define _CONS(a,b)  ((int)(a##e##b))printf(STR(A));printf("%d\n", CONS(A,A));

定义_STR这个转换宏后,从STR_STR的替换,就实现了A到2的替换,_CONS类似。

这里在举一个实际的应用:

#define  ___ANONYMOUS1(type, var, line)  type  var##line#define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line)#define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__)

例如:ANONYMOUS(static int);,如果这条语句定义在源码里的第70行,那么相当于如下语句:
static int _anonymous70;

说明如下:
第一层:ANONYMOUS(static int); –> __ANONYMOUS0(static int, __LINE__);
第二层: –> ___ANONYMOUS1(static int, _anonymous, 70);
第三层: –> static int _anonymous70;
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;

0 0
原创粉丝点击