C语言 - 预处理

Posted 一朵花花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 - 预处理相关的知识,希望对你有一定的参考价值。

C语言中编译流程:预处理 编译 汇编 链接

预定义符号

__FILE __进行编译的源文件
__LINE __文件当前的行号
__DATE __文件被编译的日期
__TIME __文件被编译的时间
__STDC __如果编译器遵守C语言标准,其值为1,否则未定义或为0

__DATE__和__TIME__最大的用途就是用来区分当前程序的版本

预处理指令

代码中 # 开头的都是预处理指令,例:#define #include…

#define

此指令用于创建一个宏定义
宏定义本质上是在预处理阶段进行文本替换

功能:

  1. 通过宏定义常量
  2. 通过宏定义类型的别名
  3. 通过宏定义一些新的"关键字" “运算符”
  4. 通过宏定义一些代码片段,实现类似函数,甚至于"泛型函数"的效果

使用宏的目的:

  1. 宏能够实现类似"泛型编程"的效果
  2. 宏能够避免函数频繁调用带来的开销

虽然宏会带来以上两个好处,但仍不建议使用宏代替函数,在C语言中,为了实现上面的两个效果,迫不得已,只能这么办,但是在C++中,针对1,有template;针对2,有inline

宏相比于函数的麻烦:

  1. 文本替换,会容易产生一些和想象中完全不一样的运算结果
  2. 宏对于参数和返回值没有类型检查
  3. 复杂的宏,不好理解且不好调试
  4. 宏不能支持递归

宏和函数的对比

属性#define定义宏函数
代码长度每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度更快存在函数的调用和返回的额外开销,所以相对慢一些
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则临近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预测
带有副作用的参数参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果函数参数只在函数调用的时候求值一次,结果更容易控制
参数类型宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的
调试宏是不方便调试的函数是可以逐语句调试的
递归宏是不能递归的函数是可以递归的

#undef

此指令用于移除一个宏定义

如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除
#define SIZE 6
#undef SIZE

条件编译

#if #else #endif #ifdef #ifndef

#if 和 #ifdef 和 #ifndef要求后面的参数是一个"常量",或者是一个"宏"(必须是编译期可以确定的值)

用法:

  1. 配合编译器选项定义宏这样的机制,实现控制调试代码是否被编译
  2. 可以通过条件编译实现跨平台
  3. 实现多行注释的效果
  4. 保证头文件只被包含一次(头文件本质上也是通过预处理的方式进行文本替换)

补充

#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.(代码片段

SQL Select 语句的用法

C语言100个经典算法源码片段

需要示例代码片段帮助

如何实现C语言的多处理器并行计算