C语言预处理详解

目录

1.预定义符号

 2.#define

1.定义常量

 2.定义宏

3.宏的替换规则

当预处理器搜索#define定义的符号的时候,字符串常量的内容并不搜索。                                                                                                                                                                                                                                         

 3.宏函数与函数的对比

 4.#和##

4.1#运算符

4.2##运算符

 5.命名约定

 6.#undef

7.命令行定义

8.条件编译

8.1 #if和#endif

 8.2#if和 #elif

 8.3在条件编译中判断宏是否被定义作为返回值

9. 头文件的包含

9.1库文件包含

9.2.本地文件


1.预定义符号

C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理阶段完成的

  1. __FILE__  //进行编译的源文件
  2. __LINE__  //文件当前的行号
  3. __DATE__  //文件被编译的日期
  4. __TIME__   //文件被编译的时间
  5. __STDC__  //如果编译器遵循ANSIC其值为1,否则未定义

 


 

 2.#define

1.定义常量

基本语法:

#define name stuff

  •  将文件中的name全部替换成stuff

 效果:

 2.定义宏

 #define允许把参数替换到文本中,这种实现通常称为宏,或者宏定义

下面是宏的申请方式:

#define name(  parament-list  )  stuff

其中的parment -list是一个由逗号隔开的符号,它们可能出现在stuff中

注意:参数列表的左括号必须与name相邻,如果出现空白字符,也会被解析成stuff的一部分

举例:

  • 这个宏接受到一个参数x ,在上述声明中,把ADD(5)置于程序中,预处理就会把5+5替换到ADD(5)

 #define 实现的是整体替换,如下列代码:

不能想当然的认为是把a+1计算成6然后再进行替换结果为36,宏定义的参数中只进行替换容易受到宏之外的表达式的影响,实际上是把a+1整体替换:a+1*a+1计算的结果为11,避免在使用宏时由于参数的操作符或相邻操作符之间不可预料的相互作用,所以在有时候()一定不能吝啬,如下图:

除此之外宏在定义的时候容易定义出带有副作用的宏参数

  1. x+1   //不带副作用
  2. x++  //带副作用

举例:

3.宏的替换规则

在程序中#define定义符号和宏时,须要涉及几个步骤。

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何#define定义的符号,若果有,就进行替换。
  2. 替换文本随后插入到程序中原来文本的位置,对于宏,参数名被他们的值替换。
  3. 最后再次对结果文件进行检查,如果还有#define定义的符号,重复上述过程。

注意:

  1. 宏参数和#define定义中可以出现其他#define定义的符号,但是对于宏,不能出现递归。
  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不搜索。                                                                                                                                                                                                           


                                 

 3.宏函数与函数的对比

 宏通常被应用于执行简单的运算。

优势:

  1. 相比调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多,所以宏比函数在程序的规模和速度方面更胜一筹
  2. 函数必须声明特定类型,函数只能在特定类型上使用,而宏不用,宏可以在任何类型中使用

劣势:

  1. 每次使用宏,一份宏定义的戴拿将插入到程序中,除非宏比较短,否者大幅度增加代码        长度。
  2. 宏无法调试
  3. 宏与类型无关,不够严谨
  4. 宏在替换的时候,会有运算符的优先级带来的问题,容易出错


 

 4.#和##

4.1#运算符

#运算符将宏的一个参数转化为字符串字面量,它允许出现在宏中

#运算符可以理解为“字符串化”要在""内

4.2##运算符

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

例如求两个数的较大值时如果是调用函数则不同的数据要写不同的的函数,相比起来,宏就更简单一点


 

 5.命名约定

一般来讲函数的宏使用语法很相似,所以语言本身没法帮我们区分

所以我们平时的习惯是:

  • 宏名全部大写
  • 函数名不要全部大写

 6.#undef

用于移除一条宏定义

 


 

7.命令行定义

用于启动编译时赋值


 

8.条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃时使用条件编译指令,相当于注释。

8.1 #if和#endif

配对使用用法和if语句类似,原型:

#if 表达式

代码块...

#endif

  • 表达式为真,则进行编译,为假则放弃编译

 8.2#if和 #elif

用法和if-else语句语句类似,只会编译一个

原型:

#if 表达式

代码块

#elif 表达式

代码块

#endif

  • 表达式为真则进行编译,表达式为假则放弃编译

 8.3在条件编译中判断宏是否被定义作为返回值

#if define(宏)

代码块

#elif  宏

代码块

#endif

另一种写法

#ifdef(宏)

代码块

#elif  宏

代码块

#endif

还有与他用法相反的#if !defined,如果没定义则编译,如果定义了则不编译

#if !defined(宏)

代码块

#endif


 

9. 头文件的包含

9.1库文件包含

#include<stdio.h>

  • C语言自带的文件一般用<>包含
  • 查找头文件直接去标准路径下去找,如果找不到就提示错误
  • 也可以用“”但是效率低一点,不容易区分是库文件还是本地文件 

9.2.本地文件

用""引用,在本地文件内查找

避免文件重复引用

#pragma once

  • 34
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熬夜苦读学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值