预处理指令#define详解

本文详细介绍了C语言预处理器中的#define指令,包括如何定义标识符和宏,以及宏展开的替换规则。通过示例说明了不正确使用括号可能导致的错误,并提供了解决方案。读者将理解#define在代码中的工作原理及其潜在问题,以及如何避免这些问题。
摘要由CSDN通过智能技术生成

预处理指令#define

#define定义标识符

语法:
#define name stuff
举例:
#define MAX 1000 //用MAX替换1000
#define reg register //为 register这个关键字,创建一个简短的名字

提问:
在define定义标识符的时候,要不要在最后加上用分号(;)?
例:
#define MAX 1000;
#define MAX 1000
建议不要加上 ; ,这样容易导致问题。 比如下面的场景:


if(condition)
 max = MAX; //这里会出现语法错误。
else
 max = 0;

#define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
下面是宏的申明方式:
#define name( parament-list ) stuff 其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意: 参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

#define SQUARE( x ) x * x

这个宏接收一个参数 x . 如果在上述声明之后,你把**SQUARE(5)**置于程序中,预处理器就会用下面这个表达式替换上面的表达式:
5 * 5
警告: 这个宏存在一个问题: 观察下面的代码段:

int a = 5;
printf("%d\n" ,SQUARE( a + 1) );

乍一看,你可能觉得这段代码将打印36这个值。 事实上,它将打印11. 为什么?
替换文本时,参数x被替换成a + 1,所以这条语句实际上变成了: printf ("%d\n",a + 1 * a + 1 );
这样就比较清晰了,由替换产生的表达式并没有按照预想的次序进行求值。
在宏定义上加上两个括号,这个问题便轻松的解决了:

#define SQUARE(x) (x) * (x)

这样预处理之后就产生了预期的效果:

printf ("%d\n",(a + 1) * (a + 1) );

这里还有一个宏定义:

#define DOUBLE(x) (x) + (x)

定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。

int a = 5; 
printf("%d\n" ,10 * DOUBLE(a)); 

这将打印什么值呢?
warning: 看上去,好像打印100,但事实上打印的是55. 我们发现替换之后:

printf ("%d\n",10 * (5) + (5)); 

乘法运算先于宏定义的加法,所以出现了
55 .
这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。

#define DOUBLE( x) ( ( x ) + ( x ) ) 

提示:
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

#define替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意:

  1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值