1. 宏定义是什么?
宏是用来表示一段代码的标识符。
宏也是标识符,也要满足标识符的规则。但通常习惯使用大写字母和下划线命名。
2. 宏定义怎么用?
宏定义通常有三种用法:
- 当作常量使用。
- 当作函数使用。
- 编译预处理。
2.1 宏定义常量
2.1.1 预定义宏
ANSI C标准定义有些定义好的宏定义,称为预定义宏。这些宏定义以双下划线__
开头结尾。
No. | 预定义宏 | 作用 |
---|---|---|
1 | __LINE__ |
当前所在文件的行号 |
2 | __FILE__ |
表示当前源文件 |
3 | __DATE__ |
文件被编译的日期 |
4 | __TIME__ |
文件被编译的时间 |
- 示例
printf("%s:%d",__FILE__,__LINE__); printf("%s:%s",__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 // 二倍的PI
2.2 带参数的宏
宏可以带参数,使用上有些像函数。这种宏称为带参数的宏。
- 语法
#define 标识符(参数...) 代码
- 示例
#define square(x) ((x)*(x)) #define cube(x) ((x)*(x)*(x))
- 试一试
是否可以不带括号?#define square(x) x*x #define cube(x) x*x*x square(10); cube(10); square(10+1); cube(10+1);
- 说明
- 上面因为缺少括号导致错误,称为宏定义边际效应,所以带参数的宏需要在一下两个位置加上括号:
- 参数出现的每个地方都要加括号。
- 整个值要加括号。
- 参数的宏也可以有多个参数
#define MIN(a,b) ((a)<(b)?(a):(b))
- 上面因为缺少括号导致错误,称为宏定义边际效应,所以带参数的宏需要在一下两个位置加上括号:
- 练习
- 变量值交换
SWAP(a,b)
- 最大值
MAX(a,b)
,最小值MIN()
- 获取数组元素个数
SIZEOF(arr)
尽量避免使用宏定义。
2.3 编译预处理
有时我们会使用没有值的宏,这种宏用于条件编译的,#ifdef
#ifndef
用于检查宏是否被定义过。控制代码的编译。
#define _DEBUG
- 示例
#ifdef TEST printf("Test\n"); #else printf("No Test\n"); #endif
3. 宏展开
宏的本质是指编译前(编译预处理阶段),用定义中的值或者代码完全替换宏的标识符。
![](https://img.haomeiwen.com/i1730134/d1a6fa93ca9558b2.png)
在gcc中可以使用
-E
或者--save-temps
,查看替换后的结果。
4. 编译预处理指令
以#
开头的都是编译预处理指令。除了宏定义,还有文件包含#include
和条件编译指令#if
、#ifdef
#ifndef
、#else
、#elif
。
- 文件包含
#include
把文件内容包含到代码中 - 条件编译指令
#if
、#ifdef
#ifndef
、#else
、#elif
根据编译条件,选择编译或者编译某段代码。
编译预处理指令不是C语言的成分,但是C语言程序离不开它们。
网友评论