C语言 - 预处理
Posted 一朵花花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 - 预处理相关的知识,希望对你有一定的参考价值。
C语言中编译流程:预处理 编译 汇编 链接
预定义符号
__FILE __ | 进行编译的源文件 |
---|---|
__LINE __ | 文件当前的行号 |
__DATE __ | 文件被编译的日期 |
__TIME __ | 文件被编译的时间 |
__STDC __ | 如果编译器遵守C语言标准,其值为1,否则未定义或为0 |
__DATE__和__TIME__最大的用途就是用来区分当前程序的版本
预处理指令
代码中 # 开头的都是预处理指令,例:#define #include…
#define
此指令用于创建一个宏定义
宏定义本质上是在预处理阶段进行文本替换
功能:
- 通过宏定义常量
- 通过宏定义类型的别名
- 通过宏定义一些新的"关键字" “运算符”
- 通过宏定义一些代码片段,实现类似函数,甚至于"泛型函数"的效果
使用宏的目的:
- 宏能够实现类似"泛型编程"的效果
- 宏能够避免函数频繁调用带来的开销
虽然宏会带来以上两个好处,但仍不建议使用宏代替函数,在C语言中,为了实现上面的两个效果,迫不得已,只能这么办,但是在C++中,针对1,有template;针对2,有inline
宏相比于函数的麻烦:
- 文本替换,会容易产生一些和想象中完全不一样的运算结果
- 宏对于参数和返回值没有类型检查
- 复杂的宏,不好理解且不好调试
- 宏不能支持递归
宏和函数的对比
属性 | #define定义宏 | 函数 |
---|---|---|
代码长度 | 每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,所以相对慢一些 |
操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则临近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数参数只在函数调用的时候求值一次,结果更容易控制 |
参数类型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型 | 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的 |
调试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递归 | 宏是不能递归的 | 函数是可以递归的 |
#undef
此指令用于移除一个宏定义
如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除
#define SIZE 6
#undef SIZE
条件编译
#if #else #endif #ifdef #ifndef
#if 和 #ifdef 和 #ifndef要求后面的参数是一个"常量",或者是一个"宏"(必须是编译期可以确定的值)
用法:
- 配合编译器选项定义宏这样的机制,实现控制调试代码是否被编译
- 可以通过条件编译实现跨平台
- 实现多行注释的效果
- 保证头文件只被包含一次(头文件本质上也是通过预处理的方式进行文本替换)
补充
#include < >,找系统目录(编译器安装所在的目录)
#include " ",先找当前项目的目录,再找系统目录
以上是关于C语言 - 预处理的主要内容,如果未能解决你的问题,请参考以下文章
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段