此文主要介绍宏定义,并在介绍宏定义时举例介绍预处理命令
预处理
参考:C 预处理器 | 菜鸟教程
重要的预处理器指令如下:
指令 | 描述 |
---|---|
#define | 定义宏 |
#include | 包含一个源代码文件 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则返回真 |
#ifndef | 如果宏没有定义,则返回真 |
#if | 如果给定条件为真,则编译下面代码 |
#else | #if 的替代方案 |
#elif | 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码 |
#endif | 结束一个 #if……#else 条件编译块 |
#error | 当遇到标准错误时,输出错误消息 |
#pragma | 使用标准化方法,向编译器发布特殊的命令到编译器中 |
预处理运算符
符号 | 描述 |
---|---|
\ | 宏延续运算符。一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符(\) |
# | 字符串常量化运算符。在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)。 |
## | 标记粘贴运算符。宏定义内的标记粘贴运算符(##)会合并两个参数。 |
defined | 预处理器 defined 运算符是用在常量表达式中的,用来确定一个标识符是否已经使用 #define 定义过。 |
宏定义
define,宏定义,C语言中预处理命令一种。分为无参宏定义和带参宏定义。
无参宏定义的一般形式为:#define 宏名 字符串
带参宏定义的一般形式为:#define 宏名(参数表) 字符串
无参宏定义
C语言中无参宏定义的一般形式为:#define 宏名 字符串
- 使用
#undef 宏名
取消已定义的宏
#define MESSAGE "Hello World!"
printf("%s\n",MESSAGE);
#undef MESSAGE
- 如果MESSAGE没有定义,则定义MESSAGE为10000
#ifndef MESSAGE
#define MESSAGE 10000
#endif
printf("%d\n",MESSAGE);
带参宏定义
带参宏定义的一般形式为:#define 宏名(形参表)字符串
- 如果MESSAGE没有定义,执行语句1;否则,执行语句2
#define MAX(a,b) a>b?a:b
#if !defined(MESSAGE)
#define MESSAGE 10000
#else
printf("%d\n",MAX(1,10));
#endif
- 如果if判断为真,则执行语句
bool flag=true;
#define PRINT(section) if(flag){\
printf("%s\n",section);\
}
PRINT("hello world!");
宏定义-定义函数
可以通过宏定义少写很多代码,大家可以看下面一串代码
#define _CONFIG_MAKE_PROTOTYPE(fname,type) type cfg_get##fname(const char *name,const type def)
_CONFIG_MAKE_PROTOTYPE(str,char*);
_CONFIG_MAKE_PROTOTYPE(num,int);
_CONFIG_MAKE_PROTOTYPE(uint8,uint8_t);
_CONFIG_MAKE_PROTOTYPE(int8,int8_t);
_CONFIG_MAKE_PROTOTYPE(uint16,uint16_t);
_CONFIG_MAKE_PROTOTYPE(int16,int16_t);
_CONFIG_MAKE_PROTOTYPE(uint32,uint32_t);
_CONFIG_MAKE_PROTOTYPE(int32,int32_t);
_CONFIG_MAKE_PROTOTYPE(uint64,uint64_t);
_CONFIG_MAKE_PROTOTYPE(int64,int64_t);
_CONFIG_MAKE_PROTOTYPE(double,double);
以_CONFIG_MAKE_PROTOTYPE(str,char*);
为例,这一行等价于什么呢?等价于:
char *cfg_getstr(const char *name, const char *def);
_CONFIG_MAKE_PROTOTYPE(fname,type);
返回类型为type类型,形参为const char *name
和类型为const type
的def
。
此时fname=str,type=char*
中,##
标记粘贴运算符,合并两个参数。将fname
和type
替换之后,即:
char *cfg_getstr(const char *name, const char *def);
对于代码的具体实现,可以如下处理:
#define _CONFIG_GEN_FUNCTION(fname,type,convname,format) \
type cfg_get##fname(const char *name,const type def) { \
paramstr *_cfg_tmp; \
for (_cfg_tmp = paramhead ; _cfg_tmp ; _cfg_tmp=_cfg_tmp->next) { \
if (strcmp(name,_cfg_tmp->name)==0) { \
STR_TO_##convname(_cfg_tmp->value); \
} \
} \
if (logundefined) { \
mfs_arg_syslog(LOG_NOTICE,"config: using default value for option '%s' - '" format "'",name,def); \
} \
COPY_##convname(def); \
}
_CONFIG_GEN_FUNCTION(str,char*,charptr,"%s")
_CONFIG_GEN_FUNCTION(num,int,int,"%d")
_CONFIG_GEN_FUNCTION(int8,int8_t,int32,"%"PRId8)
_CONFIG_GEN_FUNCTION(uint8,uint8_t,uint32,"%"PRIu8)
_CONFIG_GEN_FUNCTION(int16,int16_t,int32,"%"PRId16)
_CONFIG_GEN_FUNCTION(uint16,uint16_t,uint32,"%"PRIu16)
_CONFIG_GEN_FUNCTION(int32,int32_t,int32,"%"PRId32)
_CONFIG_GEN_FUNCTION(uint32,uint32_t,uint32,"%"PRIu32)
_CONFIG_GEN_FUNCTION(int64,int64_t,int64,"%"PRId64)
_CONFIG_GEN_FUNCTION(uint64,uint64_t,uint64,"%"PRIu64)
_CONFIG_GEN_FUNCTION(double,double,double,"%lf")