前言
提示:本文将介绍一些预定义符号和#define宏定义,宏与函数的优缺点对比等。
一、预定义符号
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
这些预定义符号都是语言内置的。
举个栗子:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
printf("file:%s line:%d\n", __FILE__, __LINE__);
return 0;
}
打印结果:
二、#define详解
1.#define定义标识符
#define name stuff //#define的一般使用形式
举个栗子:
#define MAX 1000 //将1000赋值给MAX
#define reg register //为register这个关键字,创建一个更简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break; case //在写case自动把break打上
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
data:%s\ttime:%s\n",\
_FILE_,LINE_, \
_DATA_,_TIME_)
//如果定义的stuff过长,可以分成几行写,除了最后一行,每行的后面都加上一个反斜杠(续航符)
2.#define宏定义
#define机制包括一个规定,允许把参数替换到文本中,这种实现通常称为宏或者定义和宏
#define name(parament-list) stuff //其中的parament—list是一个由逗号隔开的符号表,它们可能出现在stuff中
注意:参数列表的左括号必须与name紧邻;如果两者之间有任何空白,参数列表就会被解释为stuff的一部分。
举个例子:
#define SQUARE(x) x*x
int main()
{
printf("%d\n", SQUARE(5));
return 0;
}
运行结果:
修改一下代码:
#define SQUARE(x) x*x
int main()
{
printf("%d\n", SQUARE(5+1));
return 0;
}
打印结果:
观察这段代码,乍一看你可能觉得这个代码将打印36这个值,但是打印出来的却是11,为什么呢?
替换文本时,参数x被替换成x+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 main()
{
int x = 5;
printf("%d\n", 10 * DOUBLE(x));
return 0;
}
这将打印什么值呢?
看上去好像打印100,实际上打印的是55。
我们发现替换之后:
printf (“%d\n”,10 * (5) + (5));乘法运算优先于定义的加法,所以得出55.
解决办法就是在宏定义表达式两边加上一对括号就可以了:
#define DOUBLE( x) ( ( x ) + ( x ) )
小结
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
3.define 替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤:
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
1.宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。