用法1:方便修改,牵一发而动全身;
例如:代码中多个地方使用当前时间作为字符串,如果不使用宏定义,代码中如果有十个地方使用了当前时间这个字符串,那么我每一次编译代码,都要修改十个地方,但是如果我使用了宏定义:
#define CURRENT_TIME "14:30"
char time[]= CURRENT_TIME;
printf("current time is %s.",CURRENT_TIME);
........
这样的话,每次编译代码,我们只用修改宏CURRENT_TIME即可。
用法2:方便阅读,见名知意、精简代码;
例如:一个长方形物体,长2米,宽1.5米,高0.3米,要计算这个物体的体积并赋值给一个变量,可以这样:
float volume = 2*1.5*0.3;
也可以这样
int volume = 200*150*30;
当然还可以这样
int volume = 2000*1500*300;
上面三种方法分别是用立方米、立方厘米、立方毫米为单位,不思考一番,很难看出到底是什么意思;
如果使用宏定义表达:
#define LENGTH_M 2
#define LENGTH_CM 200
#define LENGTH_MM 2000
#define WIDTH_M 1.5
#define WIDTH_CM 150
#define WIDTH_METER 1500
#define HEIGHT_M 0.3
#define HEIGHT_CM 30
#define HEIGHT_MM 300
#define VOLUME_M3 (LENGTH_M*WIDTH_M*HEIGHT_M)
#define VOLUME_CM3 (LENGTH_CM*WIDTH_CM*HEIGHT_CM)
#define VOLUME_MM3 (LENGTH_MM*WIDTH_MM*HEIGHT_MM)
可以看到使用宏定义的代码可读性更强。
再例如:有一个数组很大,定义这个常量数组就会占用很大空间:
char fw_array[]={0xFF, 0xFB, 0xB0, 0xC0, 0x00, 0x00, 0x17, 0xB8, 0x92, 0xF7, 0x95, 0xDE, 0x00, 0x03, 0xE4,
0x32, 0xE8, 0xAB, 0x3D, 0xC0, 0x02, 0x71, 0xA2, 0x5C, 0x8D, 0xF2, 0xA0, 0xA9, 0x86, 0xA0, 0x79,
0x82, 0x82, 0xB1, 0x95, 0x85, 0x90, 0x38, 0xFD, 0x32, 0x55, 0x1F, 0x36, 0x76, 0x03, 0x36, 0xCD,
0xAB, 0x35, 0x44, 0x61, 0x33, 0x69, 0x6A, 0x39, 0xCE, 0x77, 0x39, 0x15, 0xCB, 0x34, 0x9C, 0x6B,
0x32, 0x31, 0x3A, 0x35, 0xC9, 0x52, 0x33, 0xA0, 0x3C, 0x32, 0xD5, 0x4F, 0x36, 0x15, 0x4F, 0x32,
0xB4, 0x2A, 0x38, 0xED, 0x64, 0xE8, 0x6F, 0x33, 0x4A, 0x8F, 0x49, 0x43, 0xC6, 0x20, 0x12, 0x18,
0x68, 0x10, 0x96, 0xA6, 0x0D, 0x0A, 0x98, 0x64, 0x26, 0x61, 0xC0, 0xA1, 0x84, 0x81, 0x81, 0x00,
0x46, 0xAA, 0x59, 0xF2, 0xCD, 0xA2, 0x9C, 0x0C, 0x9C, 0x86, 0x01, 0x00, 0xA7, 0x5C, 0x89, 0xAC,
0x35, 0xCA, 0x57, 0x0D, 0xAF, 0xC8, 0xE5, 0x72, 0xFE, 0xFF, 0xE7, 0x4F, 0x4F, 0x4F, 0x2C, 0xA4,
0xE6, 0xEB, 0xDB, 0xCF, 0x3C, 0xEC, 0x61, 0xCF, 0xFF, 0xFF, 0xCE, 0x90, 0x30, 0x5C, 0x1F, 0x0F,
0xE5, 0xC1, 0xF7, 0xF8, 0x62, 0x27, 0x0F, 0xF1, 0x39, 0xFC, 0xB8, 0x3F, 0xC1, 0xF3, 0xED, 0xAC, };
这样显然阅读很不方便,这时我们可以将这些没有阅读性的参数在一个单独的文件中定义为一个宏:
#define FW_ARRAY_BODY 0xFF, 0xFB, 0xB0, 0xC0, 0x00, 0x00, 0x17, 0xB8, 0x92, 0xF7, 0x95, 0xDE, 0x00, 0x03, 0xE4, \
0x32, 0xE8, 0xAB, 0x3D, 0xC0, 0x02, 0x71, 0xA2, 0x5C, 0x8D, 0xF2, 0xA0, 0xA9, 0x86, 0xA0, 0x79, \
0x82, 0x82, 0xB1, 0x95, 0x85, 0x90, 0x38, 0xFD, 0x32, 0x55, 0x1F, 0x36, 0x76, 0x03, 0x36, 0xCD, \
0xAB, 0x35, 0x44, 0x61, 0x33, 0x69, 0x6A, 0x39, 0xCE, 0x77, 0x39, 0x15, 0xCB, 0x34, 0x9C, 0x6B, \
0x32, 0x31, 0x3A, 0x35, 0xC9, 0x52, 0x33, 0xA0, 0x3C, 0x32, 0xD5, 0x4F, 0x36, 0x15, 0x4F, 0x32, \
0xB4, 0x2A, 0x38, 0xED, 0x64, 0xE8, 0x6F, 0x33, 0x4A, 0x8F, 0x49, 0x43, 0xC6, 0x20, 0x12, 0x18, \
0x68, 0x10, 0x96, 0xA6, 0x0D, 0x0A, 0x98, 0x64, 0x26, 0x61, 0xC0, 0xA1, 0x84, 0x81, 0x81, 0x00, \
0x46, 0xAA, 0x59, 0xF2, 0xCD, 0xA2, 0x9C, 0x0C, 0x9C, 0x86, 0x01, 0x00, 0xA7, 0x5C, 0x89, 0xAC, \
0x35, 0xCA, 0x57, 0x0D, 0xAF, 0xC8, 0xE5, 0x72, 0xFE, 0xFF, 0xE7, 0x4F, 0x4F, 0x4F, 0x2C, 0xA4, \
0xE6, 0xEB, 0xDB, 0xCF, 0x3C, 0xEC, 0x61, 0xCF, 0xFF, 0xFF, 0xCE, 0x90, 0x30, 0x5C, 0x1F, 0x0F, \
0xE5, 0xC1, 0xF7, 0xF8, 0x62, 0x27, 0x0F, 0xF1, 0x39, 0xFC, 0xB8, 0x3F, 0xC1, 0xF3, 0xED, 0xAC
然后在需要用到的地方只要使用这个宏就可以了
char fw_array[]={FW_ARRAY_BODY};
这样是不是更方便阅读了^_^
用法3:带参数宏定义
可以重新命名函数,例如:
int function_example(int reg,int value);
#define WRITE_REG_DATA(a,b) function_example(a,b)
做了这样的宏定义之后,在代码中使用函数function_example的地方可以用WRITE_REG_DATA代替;
可以简化表达式,例如:
比较两个数哪个大,可以这样:
int get_max_number(int a,int b)
{
return ((a)>(b)?(a) : (b));
}
也可以使用宏定义:
#define GET_MAX_NUMBER(a,b) ((a)>(b)?(a) : (b))
在代码中,使用函数get_max_number和使用宏GET_MAX_NUMBER效果是一样的,并且使用宏定义的方式效率还会更高;
用法4:特殊字符#,参数转为字符串
例如:
#define LOG_E(error) printf("%s.",#error)
这样定义之后,传入的参数就会被当做字符串,
LOG_E(Fatal Error!) 相当于 printf("%s.","Fatal Error!")
可以简单理解为,用#之后,传入的参数会被“”包裹;
用法5:特殊字符##,宏拼接
如果你想定义一个字串,但是字串的一部分是可变的,这样显然是不行的:
#define TYPE(a) the_type_is_a
#define TYPE(a) the_type_is_ a
#define TYPE(a) the_type_is_(a)
#define TYPE(a) the_type_is_ (a)
我们想要把a当做参数来用拼接进宏定义的对象中,我们可以这样用:
#define TYPE(a) the_type_is_##a
这样定义之后,##会告诉预编译器:先把我前后要替换的参数替换了,然后将我前后拼接到一起。
TYPE(int) 经过预编译之后会变成 the_type_is_int
用法6:C语言中的特殊宏
__DATE__:在源文件中插入当前的编译日期
__TIME__:在源文件中插入当前编译时间;
__FILE__:在源文件中插入当前源文件名;
__LINE__:在源代码中插入当前源代码行号;
__FUNCTION__:在源代码中插入当前所在函数名称;
__STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
__cplusplus:当编写C++程序时该标识符被定义。