预编译(预处理)详解

目录

1.预定义符号

2.#define定义常量

3.#define定义宏

4.带有副作用的宏参数

5.宏的替换规则

6.宏与函数的对比

7.#和##

7.1 #运算符

7.2 ##运算符

 8.命名约定

9.#undef

10.条件编译

11.头文件的包含

11.1本地文件的包含

11.2标准库中文件的包含



1.预定义符号

c语言设置了一些预定义符号,可以直接使用,预定义符号就是在预处理期间处理的:

1.__FILE__     进行编译的原文件

2.__LINE__     这个符号所在的行号

3.__DATE__    文件被编译的日期

4.__TIME__     文件被编译的时间

5.__STDC__    如果编译器遵顼ANSIC,其值为1,否则未定义(visual studio的编译器并没有__STDC__)

2.#define定义常量

语法形式:#define  name   stuff

预处理阶段会将#define的name全部完全的替换成stff,然后将#define删除。

注意:在#duffine定义的时候不要在后面加分号,因为替换的时候会将分号也替换进去。

3.#define定义宏

#define机制包括一个规定:允许把参数替换到文本中,这种实现就是宏。

宏的申明方式:#define name(parament-list)  stuff    注:parament-list是一个由逗号隔开的符号表,他们可能出现在stuff中

注意:参数列表的左括号必须跟name紧邻,否则将理解为:参数列表也是后面内容的一一部分。

当我们使用这个宏的时候,会将数值(假如说是x)传给n,然后替换为((x)*(x))。

没错这确实很像c++中的内联函数,感兴趣可以去看一下这个c++入门 (蒟蒻版)-CSDN博客

这里读者可能会注意到我的宏写了好多括号,这是很有必要的,因为宏的机制是完全的替换,可能会因为参数中的操作符或者邻近的操作符之间的优先级问题,造成非预期的结果。

4.带有副作用的宏参数

当宏的参数在宏定义中出现不止一次,如果参数带有副作用,那么可能会出现不可预测的后果。如x+1就没有副作用,x++就有副作用。 看下面代码:

解释:从左到右依次计算,后置++是先使用后++,所以是8>1,然后执行++后a为9,b为2。再执行后面a++(b++不会执行)和赋值给z的操作,因为后置++,所以先赋值给z再++。所以最后z=9,a=10,b=2。

5.宏的替换规则

1.在调用宏的时候,首先对参数进行检查,如果包含被#define定义的符号(#define定义常量),那么他们先被替换。

2.替换文本随后被插入到原来开的位置。对于宏。参数名被他们的值所代替。

3.最后再次对结果进行扫描,看是否存在#define定义的符号,若有重上述步骤。

注意:宏参数和#define定义中可以出现其他的#define定义的符号。但是不能出现递归。

当预处理器搜索#define定义的符号时,字符串常量当然是不会被搜索的

6.宏与函数的对比

宏就像杀鸡刀:迅速但只能杀杀鸡

函数像杀牛刀:相对慢但能杀牛

宏的优势:

对于简单的运算可以考虑使用宏,为什么不用函数。有句话叫杀鸡焉用宰牛刀,函数的执行效率比宏要慢规模更大,宏是直接的替换,而函数还要建立函数栈帧,再执行里面的操作,再返回值。

并且函数的参数必须要声明类型,而宏不需要,所以宏的范围更广。

宏的劣势:

每次使用宏,都要替换,如果宏比较长,会大幅的增加程序长度。

宏无法被调试。

宏没有类型,也就不够严谨。

宏可能带来优先级的问题,容易出错。

但是如果你的参数是类型名的话,函数是无法做到的,但是宏可以。比如:

7.#和##

7.1 #运算符

#运算符将宏的一个参数转换为字符串字面量。它仅允许出现在带有参数的宏的替换列表中。

#运算符所执行的操作可以理解为字符串化

(为什么要有这个操作符,因为我们在使用宏的时候不是都想替换成值,而是替换之后的字符串)例如:

7.2 ##运算符

##可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。##被称为记号粘合,这样的链接必须产生一个合法的标识符,否则其结果就是未定义的。例如:

这种代码认识就好了,一般没人这么写

 8.命名约定

习惯是:把宏名全部大写,函数名不要全部大写。

9.#undef

这条指令用来移除一个宏定义。

10.条件编译

满足条件参与编译,不满足条件不参与编译。(注意这里都是在预处理的时候处理的,创建的变量是还没有出现的)

#if 常量表达式

#elif 常量表达式

#elif......

#else 常量表达式

#endif (判断到此结束)

#ifdef  ()等价于#if defined () 意思就是判断()中的符号是否被定义过了。

#ifndef()等价于#if !defined()判断()中的符号是否没有定义过。

注意:这里的if elif else 跟if else if  else用法完全类似,可以嵌套使用

11.头文件的包含

11.1本地文件的包含

#include "  "

查找策略:现在源文件所在目录下查找,如果没有找到,就像查找库函数头文件一样在标准位置查找头文件。再找不到就编译报错。

11.2标准库中文件的包含

#include <    >

注意包含可能会嵌套。

到这就结束了.......

  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值