C语言笔记之宏定义
1. 宏定义是什么?
宏是用来表示一段代码的标识符。
宏也是标识符,也要满足标识符的规则。但通常习惯使用大写字母和下划线命名。
2. 宏定义怎么用?
宏定义通常有三种用法:
- 当作常量使用。
- 当作函数使用。
- 编译预处理。
2.1 宏定义常量
2.1.1 预定义宏
ANSI C标准定义有些定义好的宏定义,称为预定义宏。这些宏定义以双下划线__
开头结尾。
No. | 预定义宏 | 作用 |
---|---|---|
1 | __LINE__ |
当前所在文件的行号 |
2 | __FILE__ |
表示当前源文件 |
3 | __DATE__ |
文件被编译的日期 |
4 | __TIME__ |
文件被编译的时间 |
- 示例
printf("%s:%d\n",__FILE__,__LINE__);
printf("%s:%s\n",__DATE__,__TIME__);
**注:**显示的时间为编译完成的时间,之后再运行程序,编译时间是不会改变的
2.1.2 自定义宏
除了使用标准定义的宏,可以使用#define
指令用来定义一个宏。
- 语法
#define 标识符 值
- 示例
#define PI 3.1415926
- 说明
- 注意没有结尾的分号,因为不是C的语句。
- 名字必须是一个单词,值可以是各种东西。
- 在C语言的编译器开始之前,编译预处理程序会把程序中的名字换成值。是完全的文本替换。
- 如果一个宏的值有其他宏的名字,也会被替换。
#define PI_2 2*PI
- 如果一个宏的值超过一行,最后一行之前行末需要加\。
//#define PI_2 2*PI
#define PI_2 2 \
* \
PI
- 宏的值后面出现的注释不会被当做宏的值的一部分。
2.2 带参数的宏
宏可以带参数,使用上有些像函数。这种宏称为带参数的宏。
- 语法
#define 标识符(参数...) 代码
- 示例
#define square(x) ((x)*(x))
#define cube(x) ((x)*(x)*(x))
是否可以不带括号?答案是否定的,参考如下代码
- 说明
上面因为缺少括号导致错误,称为宏定义边际效应,所以带参数的宏需要在一下两个位置加上括号:
-
参数出现的每个地方都要加括号。
-
整个值要加括号。
参数的宏也可以有多个参数
#define MIN(a,b) ((a)<(b)?(a):(b))
小例:
- 变量值交换
SWAP(a,b)
#define SWAP(a,b) {int t=a;a=b;b=t;}
- 最大值
MAX(a,b)
,最小值MIN()
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
在写代码的时候,应尽量避免使用宏定义。
2.3 编译预处理
有时我们会使用没有值的宏,这种宏用于条件编译的,#ifdef
#ifndef
用于检查宏是否被定义过。控制代码的编译。
#define _DEBUG
- 示例
#ifdef TEST
printf("Test\n");
#else
printf("No Test\n");
#endif
3. 宏展开
宏的本质是指编译前(编译预处理阶段),用定义中的值或者代码完全替换宏的标识符。
在Linux下gcc中可以使用-E或者–save-temps,查看替换后的结果。
4. 编译预处理指令
以#
开头的都是编译预处理指令。除了宏定义,还有文件包含#include
和条件编译指令#if
、#ifdef
#ifndef
、#else
、#elif
。
- 文件包含
#include
把文件内容包含到代码中 - 条件编译指令
#if
、#ifdef
#ifndef
、#else
、#elif
根据编译条件,选择编译或者编译某段代码。