预处理:程序员所编译C代码不能被直接编译

文章详细介绍了C语言中的预处理概念,包括预处理指令如#include和#define,以及宏替换、宏常量和宏函数的使用。预处理指令用于导入头文件和进行文本替换,宏则提供了一种代码替换机制,但宏使用需谨慎,可能导致代码冗余和安全性问题。宏函数虽执行速度快,但缺乏类型检查和递归支持。文章还对比了宏函数与普通函数的优缺点,指出宏函数适合于执行频繁但对返回值无要求的场景。
摘要由CSDN通过智能技术生成

它需要一段程序把它先翻译一下,被翻译过程预处理,负责翻译的程序叫预处理器,被翻译的指令叫预处理指令,C代码中以#开头的都是预处理指令。

gcc -E xxx.c 查看C代码的预处理结果,显示在终端
gcc -E xxx.c -o xxx.i 把预处理的结果保存到文件中,以.i结尾的文件也被称为预处理文件。
文件包含指令:

#include 预处理指令的功能是导入一个头文件到当文件中,它用两中使用方法:

方法1:#include <file_name.h>

从系统指定的路径查找并导致头文件,一般用于导入标准库、系统、第三方库的头文件。

注意:通过设置操作系统的环境,编译器的-I参数来指定头文件的查找路径。

方法2:#include "file_name.h"

从系统当前路径查找并导致头文件,如果没有再从系统指定的路径查找并导致头文件,一般用于导入自定义头文件。

宏替换指令:
定义宏名:

#define 宏名 [会被替换的内容]

使用宏名:

printf("%d\n",宏名);

注意:在预处理阶段,预处理器会把代码使用的宏名替换成宏名后面的那段内容。

宏常量:

#define 宏名 字面值数据

给没有意义的字面值数据,取一个有意义名字,代替它,这样可以提高代码的可读性、可扩展性,还可以方便代码扩展。

宏表达式:

#define 宏名 表达式、操作、更复杂的标识符

#define STU_FORMAT "%s %c %hd %d"
#define sf scanf
#define YEAR_SEC (3600*24*365ul)
定义宏常量和宏表达式要注意的问题:

由于宏常量和宏表达式可能使用在表达式中,因此在定义宏常量和宏表达式的末尾不要加分号。

枚举常量与宏常量的区别:

提前:它们都可以提高代码的可读性,给没有意义字面值数据取一个有意义的名字。

1、从安全角度来说枚举常量要比宏常量安全,因为宏常量是通过替换实现的,在替换过程中可能会导致新的错误,如:有与宏名重名和函数或变量。

2、但枚举常量没有宏常量方便,枚举常量只能是整型数据,而宏常量可以是任何类型的,甚至是复杂的表达式,宏常量的使用范围更广。

总结:如果是大量的整型字面值数据建议定义为枚举常量,如果少量的或整型以外的类型的字面值数据建议定义为宏常量。

预定义的宏:
编译器预定义的宏:
__FILE__ 获取当前文件名
__func__ 获取当前函数名
__LINE__ 获取当前行号
__DATE__ 获取当前日期
__TIME__ 获取当前时间
__WORDSIZE 获取当前编译器的位数
// 适合用来显示警告、错误信息。
宏函数:
什么是宏函数:

宏函数不是真正的函数,而是带参数的宏替换,只是使用方法像函数而已。

在代码中使用宏函数,预处理时会经历两次替换,第一次把宏函数替换成它后面的一串代码、表达式,第二次把宏函数中的参数替换到表达式中。

定义宏函数要注意的问题:

1、如果宏函数后面的代码有多行,可以使用大括号包括,进行保护。

2、宏函数后面的代码不能直接换行,如果代码确定太长,可以使用续行符换行。

3、使用了大括号保护的宏函数,在使用时末尾可以不加分号,为了统一语法的一致性,强制使用者在宏函数末尾加分号,可以使用do while语句来实现。

4、为了防止宏函数出现二义性,对宏参数要尽量多加小括号。

二义性:就是使用宏函数的环境不同、参数不同,造成宏函数有多执行规则,会出现出乎意料的执行结果,这种宏函数的二义性,设计宏函数时要尽量杜绝。

调用宏函数要注意的问题:

1、传递给宏函数的参数不能使用自变运算符,因为我们无法知道参数在宏代码中会被替换多少次。

2、宏函数没有返回值,只是个别宏函数表达式有计算结果。

普通函数与宏函数的优缺点?
宏函数的优点:

1、执行速度快,它不是真正的函数调用,而是代码替换,不会经历传参、跳转、返回值。

2、不会检查参数的类型,因此通用性强。

宏函数的缺点:

1、由于它不是真正的函数调用,而是代码替换,每使用一次,就会替换出一份代码,会造成代码冗余、编译速度慢、可执行文件变大。

2、没有返回值,最多可以有个执行结果。

3、类型检查不严格,安全性低。

4、无法进行递归调用。

普通函数的优点:

1、不存在代码冗余的情况,函数的代码只会在代码段中存储一份,使用时跳转过去执行,执行结束后再返回,还可以附加返回值。

2、安全性高,会对参数进行类型检查。

3、可以进行递归调用,实现分治算法。

函数的缺点:

1、相比宏函数它的执行速度慢,调用时会经历传参、跳转、返回等过程,该过程耗费大量的时间。

2、类型专用,形参什么类型,实参必须是什么类型,无法通用。

什么样的代码适合封装成宏函数?

1、代码量少,即使多次使用也不会造成代码段过度冗余。

2、调用次数少,但执行次数多,也就是宏函数会在循环语句中调用。

3、函数的功能对返回值没有要求,也就是函数的功能不是通过返回值达到的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxj555281

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值