首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >#C语言——学习攻略:攻克 预处理(上),根本不在话下!

#C语言——学习攻略:攻克 预处理(上),根本不在话下!

作者头像
晨非辰Tong
发布2025-12-23 13:40:24
发布2025-12-23 13:40:24
1010
举报
文章被收录于专栏:C++C++

1. 预定义符号

--C语言设置了预定义符号,直接使用(预处理符号在预处理阶段处理)。

代码语言:javascript
复制
__FILE__//进行编译的源文件
__LINE__//文件当前行号
__DATE__//文件编译的日期
__TIME__//文件编译的时间
__STDC__//若编译器遵循标准c,值为1,否则未定义
代码语言:javascript
复制
//使用
int main()
{
	printf("%s\n", __FILE__);
	printf("%d\n", __LINE__);
	printf("%s\n", __DATE__);
	printf("%s\n", __TIME__);
	return 0;
}


2. #define 定义常量(命名约定)

代码语言:javascript
复制
//基本形式
#define NAME STUFF

NAME:宏的名称,通常使用全大写字母和下划线来命名.(函数名不要全大写)
STUFF:替换体,代表将要替换 NAME 的任何文本。
代码语言:javascript
复制
//例子
#define MAX 1000
#define reg register//register关键词,更简短的形式代替
#define do_forever for(;;)//替换死循环
#define CASE break;case //switch预语句,写case自动加上break
#define DEBUG_PRINT printf( "file:%s\t  line:%d\t  date:%s\t  time:%s\n",\
							__FILE__,__LINE__,\
							__DATE__,__TIME__)

--对于最后一条,原因代码太长,为了全部展现在要分行处的末尾紧跟着加 ' \ '(不能有空格)

--那为什么不在定义语句后面加分号?

代码语言:javascript
复制
#define MAX 1000
#define MAX 1000;

--由于宏定义本身特点,会将STUFF出的内容全部展现,包括' ; ',可能导致语句出现两个分号,出现错误。


3. #define 定义宏

3.1 方法、注意事项

--#define机制包括一个规定,允许将参数替换到文本中,通常称为宏或定义宏。

代码语言:javascript
复制
//形式
#define NAME(parament-list) STUFF

--( parament-list )是由逗号隔开的符号表,它们可能出现在stuff中。 --括号紧挨NAME,两者之间有任何空白存在,参数列表会被解释为stuff的一部分(相当与定义宏常量)。

--错误1:

代码语言:javascript
复制
#define SQUARE(x) x*x
int main()
{
	int a = 5;
	int ret1 = SQUARE(a);//25
	//宏接受参数a-5,5*5再替换宏,得到ret1 = 25

	int ret2 = SQUARE(a+1);//11
	//为什么不输出36?
	//接收后形式:a + 1 * a + 1;优先级——>先乘法,再加法
	printf("%d\n%d\n", ret1, ret2);
	return 0;
}

--解决:

代码语言:javascript
复制
#define SQUARE(x) (x)*(x)
//先给宏定义文本个体加括号,解决优先级问题

int main()
{
	int a = 5;
	int ret1 = SQUARE(a);//25
	
	int ret2 = SQUARE(a+1);//36
	printf("%d\n%d\n", ret1, ret2);
	return 0;
}

--错误2:

代码语言:javascript
复制
#define DOUBLE(X) (X)+(X)

int main()
{
	int a = 5;
	int ret = 10 * DOUBLE(a);//55
    //为什么不输出100?
    //接收形式:10 * 5 + 5,又是优先级问题
    
	printf("%d\n", ret);
	return 0;
}

--解决:

代码语言:javascript
复制
#define DOUBLE(X) ((X)+(X))
//文本整体再加括号

int main()
{
	int a = 5;
	int ret = 10 * DOUBLE(a);//100
	printf("%d\n", ret);
	return 0;
}

3.2 副作用的宏

--当宏参数在宏定义中出现超过一次时,若参数有副作用,那在用宏时可能出现危险,导致错误。副作用就是表达式求值的时候出现的永久性效果(改变了参数数值)。

代码语言:javascript
复制
//比如简单的+1操作
x + 1//正常
x++//副作用,改变了x值
代码语言:javascript
复制
#include<stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
	int x = 5;
	int y = 8;
	int z = MAX(x++, y++);
	printf("x=%d y=%d z=%d", x, y, z);
	return 0;
}

副作用 --首先 z 经预处理后:z = ((x++) > (y++) ? (x++) : (y++));——>先比较x、y值。 --由于是后置操作先使用在操作,x、y值都+1后进行——>x = 6,y = 9,z = 9。 --最后y在进行后置操作,y = 10。 (对于函数则是先计算完再传参)


3.3 宏替换规则

--程序中拓展#define定义符号和宏时,有几个步骤:

  • 调用宏时,先对参数进行检查,是否包含任何由#define定义的符号,有——>被替换。
  • 替换文本(STUFF)被插入到程序中原来文本(NAME)位置,对于宏——>参数名被值替换。
  • 最后再次对操作过的文件进行扫描,检查是否含任何由#define定义的符号,有——>重复以上流程。

--注意:

  • 宏参数和#define 定义中可出现其他#define定义的符号。但对于宏,不能出现递归。
  • 当预处理器搜索#define定义的符号时,字符串常量的内容不被搜索。
代码语言:javascript
复制
//解释字符串内容不被搜索
#define M 100
int main()
{
	int ret = M;
	printf("M:%d\n", M);
	return 0;
}

输出:M:100

4. 宏对比函数

--宏被应用于简单的运算:

代码语言:javascript
复制
//找出两值的较大值
#define MAX(a, b) ((a) > (b)?(a):(b))
int main()
{	
	int a = 6;
	int b = 2;
	int ret = MAX(a, b);
	printf("MAX:%d\n", ret);
	return 0;
}

--为什么用宏?不用函数?

  • 用于调函数、函数返回的代码可能比实际执行这个小型计算工作所需时间更多。所以宏比函数在程序规模和速度方面更优。
  • 更重要是函数的参数必须声明为特定类型,则函数只能在类型合适表达式上用。反之宏可以用于整形、长整型、浮点型等可以用 " > " 来比较的类型。宏的参数与类型无关。

--劣势:

  • 每次用宏时,一份宏定义的代码插到程序中。除宏比较短外,则可能大幅度增加程序长度。
  • 宏无法调试。
  • 宏由于类型无关——>不严谨。
  • 宏会带来运算符优先级问题,处理不当会出错。

--对比表:

属性

#define定义宏

函数

代码长度

每次使用,宏代码会插入到程序。除了非常小的宏外,程序长度被大幅增长

函数代码只出现一个地方;每次使用时,调用那地方的同份代码

执行速度

更快

存在函数的调用和返回的额外开销,相对慢

操作符优先级

宏参数的求值是在周围所有表达式的上下文环境里,除非加上括号,否则邻近操作符优先级会产生与预想不同,建议写宏时多写括号

函数参数只在函数调用时求值一次,结果值传给函数,表达式求值结果易预测

副作用参数

参数可能被替换到宏体中多个位置,若宏参数被多次计算,带有副作用的参数求值可能产生不可预料的结果

函数参数只在传参时求值一次,结果易控制

参数类型

宏参数与类型无关,只要对参数的操作是合法的,就可以用于任何类型

函数参数和函数类型有关,参数类型不同,需要不同函数,即使执行的任务是不同的

调试

不方便调试

可以逐语句调试

递归

不可以

可以

相关系列回顾:

#C语言——学习攻略:攻克 文件操作内容(一),根本不在话下!

#C语言——学习攻略:攻克 文件操作内容(二),根本不在话下!

#C语言——学习攻略:攻克 编译与链接,根本不在话下!

结语:本篇文章到此结束,对于C语言相关知识大家要多次回顾,如果这篇文章对你的学习有帮助的话,欢迎一起讨论学习,你这么帅、这么美给个三连吧~~~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 预定义符号
  • 2. #define 定义常量(命名约定)
  • 3. #define 定义宏
    • 3.1 方法、注意事项
    • 3.2 副作用的宏
    • 3.3 宏替换规则
  • 4. 宏对比函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档