嵌入式C语言-预编译命令(#define、#if、#ifdef、#ifndef、#undef)

#define

宏定义

#define机制包含了一个规定,允许把参数替换到文本中,这种实现通常称为宏定义。下面是宏的声明方式:

#define name(parameter-list)	stuff

其中,parameter-list(参数列表)是由逗号分割的符号列表,它们可能出现在stuff中。name必须与左括号紧邻。比如下面的例子:

#define MAX(a,b)	(a)>(b)?(a) : (b)

提示
所有用于数值表达式进行求值的宏定义的参数都应该用括号,避免在使用宏时,由于宏展开导致参数中的操作符或邻近操作符之间发生不可预测的情况。

#define 替换

在程序中扩展#define定义符号和宏时,需要注意几个事项:

  • 宏不可以出现递归
  • #define定义符号时,字符串常量的内容不进行检查

带副作用的宏参数

当宏参数的宏定义中出现的次数超过一次时,如果这个参数具有副作用,那么当你使用这个宏时就可能出现危险,导致不可预测的结果。例如,下面的表达式:

x+1;

可以重复执行几百次,它每次获得结果都是一样。这个表达式不具有副作用。但是

i++;

就具有副作用:它增加x的值。MAX宏可以证明具有副作用的参数所引起的问题。观察下列代码,你觉得最终输出的是什么??

#define MAX(a,b)	((a)>(b)?(a):(b))
...
x = 5;
y = 8;
z = MAX(x++,y++);

带副作用参数问题解决并轻松。记住第1个表达式是一个条件表达式,用于确定执行另两个表达式中的那一个,剩余的表达将不会执行。结果是:x=6,y=10,z = 9;
对于这个结果是不是感觉很惊讶,只要检查一下宏替换产生的代码,就一目了然了。
z = (x++)>(y++)?(x++):(y++);
讲解:

  1. 执行x++,y++表达式分别得到x=6,y=9;
  2. 执行>运算表达式;
  3. 执行赋值操作z = 9;
  4. 执行y++得到y=10;

undef

这条预处理指令用于移除一个宏定义。
#undef name
如果一个现存的名字需要被重新定义,那么它的旧的首先必须要用#undef移除。

#ifdef log_e
#undef log_e	//移除之前旧的宏定义log_e
#endif

条件编译

概念

条件编译(conditional compiling)命令指定预处理器依据特定的条件判断保留或删除某段源代码。例如,可以使用条件编译让源代码适用与不同的目标系统,而不需要管理该源代码的各种版本。

条件编译区域以#if、#ifdef或#ifndef等命令作为开头,以#endif命令结尾。条件编译区域可以有任意数量的#elif命令,但最多一个#else命令。下面显示它最简单的语法:

#if constant-expression
	statements
#endif

其中,constant-expression常量表达式)由预处理器进行求值。如果它的值是非零(真),那么statements部分被正常编译,否则预处理器就安静地删除它们。

#if和#elif命令

作为#if或#elif命令条件的表达式,必须是整数常量预处理器表达式。这与普通的整数常量表达式不同,主要的区别在于:

  • 不能在#if或#elif表达式中使用类型转换运算符。
  • 可以使用预处理运算符defined。
  • 在预处理器展开所有宏,并且计算完所有 defined 表达式之后,会使用字符 o 替换掉表达式中所有其他标识符或关键字。

defined运算符

一元运算符defined可以出现在#if或#elif命令的条件中。它的形式如下:

#defined 标识符
#defined (标识符)

如果指定的标识符(identifier)是一个宏名称(也就是说,它被#define命令定义,并且未被#undef命令取消定义),则defined表达式会生产值1。否则,defined表达式会生产值0。

#if和defined相结合

如果defined用宏定义标识符执行,未定义则编译。如下所示:

#define DEBUG

#if defined(DEBUG)
// 宏定义DEBUG执行
#else
// 取消宏定义DEBUG不执行
#endif

defined运算符相对于#ifdef和#ifndef 命令的优点是:你可以在更大型的预处理器表达式中使用它的值。如下例所示:

#if defined( __unix__ ) && defined( __GNUC__ )
/* ... */
#endif

大多数编译器会提供预定义宏,例如上例所使用的宏,它用来识别目标系统和编译器。因此,在 Unix 系统中,通常预先定义好了宏 unix,而 GCC 编译器则会预先定义好了宏 GNUC。类似地,微软 Windows 平台上的 Visual C 编译器会自动定义好宏 _WIN32 和宏 _MSC_VER。

#ifdef 和 #ifndef 命令

通过#ifdef和#ifndef命令测试某个宏定义是否已被定义。它们的语法是:

#ifdef 标识符
#ifndef 标识符

这等同于下面的#if命令:

#if defined 标识符
#if !defined 标识符

如果 identifier(标识符) 不是宏名称,则 #ifndef 标识符后面的条件代码被保留。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值