Skip to content

Latest commit

 

History

History
86 lines (61 loc) · 4.29 KB

13-预处理.md

File metadata and controls

86 lines (61 loc) · 4.29 KB

预处理

C语言源文件要经过编译、链接才能生成可执行程序:

  • 编译(Compile)会将源文件(.c文件)转换为目标文件。对于VC/VS,目标文件后缀为 .obj;对于GCC,目标文件后缀为 .o
  • 链接(Link)是针对多个文件的,它会将编译生成的多个目标文件以及系统中的库、组件等合并成一个可执行程序。

但是在编译和连接之前,通常还有一个步骤——预处理


1 C 预处理器

C预处理器不是编译器的组成部分,它是编译过程中一个单独的步骤。C预处理器只是一个文本替换工具, 它们会指示编译器在实际编译之前完成所需的预处理。通常将把C预处理器(C Preprocessor)简写为 CPP。

所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。

预处理指令

  • define:定义宏
  • include:包含一个源代码文件
  • undef:取消已定义的宏
  • ifdef:如果宏已经定义,则返回真
  • ifndef:如果宏没有定义,则返回真
  • if:如果给定条件为真,则编译下面代码
  • else:#if 的替代方案
  • elif:如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
  • endif:结束一个 #if……#else 条件编译块
  • error:当遇到标准错误时,输出错误消息
  • pragma:使用标准化方法,向编译器发布特殊的命令到编译器中

预定义宏

  • __DATE__:当前日期,一个以 "MMM DD YYYY" 格式表示的字符常量。
  • __TIME__:当前时间,一个以 "HH:MM:SS" 格式表示的字符常量。
  • __FILE__:这会包含当前文件名,一个字符串常量。
  • __LINE__ :这会包含当前行号,一个十进制常量。
  • __STDC__ :当编译器以ANSI标准编译时,则定义为 1。
  • __STDC_VERSION__ :为C99时设置为199901L
  • __VA_ARGS__:用于定义带参数的宏时说明参数是可变参数

务必要注意: 预处理器只是一个文本替换工具


2 #include命令

#include是文件包含命令,主要用来引入对应的头文件。#include的处理过程很简单,就是将头文件的内容插入到该命令所在的位置, 从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。

包含标准库的头文件用尖括号,包含自定义的头文件用双引号。


3 明示常量:#define

#define用于定义宏,宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。一般用于定义常量或者表达式

宏定义注意:

  • 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的替换。字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
  • 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。、
  • 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。
  • 宏定义与typedef是不一样的。 typedef是类型定义,是有类型的。宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。

4 条件编译

能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。条件编译是预处理程序的功能,不是编译器的功能。

if、ifdef、ifndef等预处理指令用于实现条件编译。条件编译在预处理阶段完成的,多余的代码以及所有的宏都不会参与编译,不仅保证了代码的正确性,还减小了编译后文件的体积。


5 #error和#line

#line用于重置由 __LINE____FILE__宏报告的行号和文件名,使用方式为

#line 1000//重置行号
#line 2000 "aa.c"//重置行号和文件名

#error指令使预处理器发出一条错误信息,该消息包含指令中的文本。可能的话编译过程应该被终端。使用方式为

#if __STDC_VERSION__ == 1999901L
#error NOT C99
#endif