C语言编译预处理 女爷i 2021-11-09 05:18 403阅读 0赞 C语言由源代码生成可执行程序的过程如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 其中编译预处理阶段,读取C源程序,对其中的预处理指令(以\#开头的指令)和特殊符号进行处理。或者说是扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。 预处理过程先于编译器对源代码进行处理,读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行转换。预处理过程还会删除程序中的注释和多余的空白字符。 # 预处理指令 # 在C语言的程序中可包括各种以符号\#开头的编译指令,这些指令称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分。通过预处理命令可扩展C语言程序设计的环境。 预处理指令是以\#号开头的代码行。\#号必须是该行除了任何空白字符外的第一个字符。\#后是指令关键字,在关键字和\#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。 预处理指令主要有以下三种: 1)包含文件:将源文件中以\#include格式包含的文件复制到编译的源文件中,可以是头文件,也可以是其它的程序文件。 2)宏定义指令:\#define 指令定义一个宏,\#undef指令删除一个宏定义。 3)条件编译:根据\#ifdef和\#ifndef后面的条件决定需要编译的代码。 # 包含文件 # 当一个C语言程序由多个文件模块组成时,主模块中一般包含main函数和一些当前程序专用的函数。程序从main函数开始执行,在执行过程中,可调用当前文件中的函数,也可调用其他文件模块中的函数。 如果在模块中要调用其他文件模块中的函数,首先必须在主模块中声明该函数原型。一般都是采用文件包含的方法,包含其他文件模块的头文件。 文件包含中指定的文件名即可以用引号括起来,也可以用尖括号括起来,格式如下: \#include< 文件名> 或 \#include“文件名” 如果使用尖括号<>括起文件名,则编译程序将到C语言开发环境中设置好的 include文件中去找指定的文件。 因为C语言的标准头文件都存放在include文件夹中,所以一般对标准头文件采用尖括号;对编程自己编写的文件,则使用双引号。 如果自己编写的文件不是存放在当前工作文件夹,可以在\#include命令后面加在路径。 \#include命令的作用是把指定的文件模块内容插入到\#include所在的位置,当程序编译链接时,系统会把所有\#include指定的文件链接生成可执行代码。文件包含必须以\#开头,表示这是编译预处理命令,行尾不能用分号结束。 \#include所包含的文件,其扩展名可以是“.c”,表示包含普通C语言源程序。也可以是 “.h”,表示C语言程序的头文件。C语言系统中大量的定义与声明是以头文件形式提供的。 # 宏定义指令 # 使用\#define命令并不是真正的定义符号常量,而是定义一个可以替换的宏。被定义为宏的标识符称为“宏名”。在编译预处理过程时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏替换”或“宏展开”。 在C语言中,宏分为有参数和无参数两种。 ## 1、无参数的宏 ## 其定义格式如下: \#define 宏名 字符串 在以上宏定义语句中,各部分的含义如下: **\#** 表示这是一条预处理命令(凡是以“\#”开始的均为预处理命令)。 **define** 关键字“define”为宏定义命令。 **宏名** 是一个标示符,必须符合C语言标示符的规定,一般以大写字母标识宏名。 **字符串** 可以是常数,表达式,格式串等。在前面使用的符号常量的定义就是一个无参数宏定义。 注意:预处理命令语句后面一般不会添加分号,如果在\#define最后有分号,在宏替换时分号也将替换到源代码中去。在宏名和字符串之间可以有任意个空格。 \#define PI 3.141592 **示例(book149.c)** ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70][] 执行预编译指令gcc -E -o book149.E book149.c,得到book149.E文件,如下: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 1][] 在使用宏定义时,还需要注意以下几点: 宏定义是宏名来表示一个字符串,在宏展开时又以该字符串取代宏名。这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层替换。 习惯上宏名用大写字母表示,以方便与变量区别。但也可以用小写字母。 ## 2、带参数的宏 ## \#define命令定义宏时,还可以为宏设置参数。与函数中的参数类似,在宏定义中的参数为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,还要用实参去代换形参。 带参宏定义的一般形式为: \#define 宏名(形参表) 字符串 在定义带参数的宏时,宏名和形参表之间不能有空格出现,否则,就将宏定义成为无参数形式,而导致程序出错。 \#define MAX(x,y) ((x)>(y) ? (x) : (y)) 以上的宏定义中,如果x的值大于y,得到x,否则得到y。 示例(book150.c) ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 2][] 运行结果 ![20190805081706245.png][] 带参的宏和带参的函数相似,但其本质是不同的。使用带参宏时,在预处理时将程序源代码替换到相应的位置,编译时得到完整的目标代码,而不进行函数调用,因此程序执行效率要高些。而函数调用只需要编译一次函数,代码量较少,一般情况下,对于简单的功能,可使用宏替换的形式来使用。 带参数的宏不容易理解,所以,在实际开发中,我不建议使用带参数的宏。 # 条件编译 # 条件编译有多种格式,在这里我只介绍最常用的两种格式\#ifdef和\#ifndef。 ## 1、\#ifdef ## \#ifdef命令的使用格式如下: \#ifdef 标识符 程序段 1 \#else 程序段 2 \#endif 其意义是,如果\#ifdef后面的标识符已被定义过,则对“程序段1”进行编译;如果没有定义标识符,则编译“程序段2”。一般不使用\#else及后面的“程序2”。 示例(book153.c) ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 3][] 执行预编译指令gcc -E -o book153.E book153.c,得到book153.E文件,如下: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 4][] ## 2、\#ifndef ## 而\#ifndef的意义与\#ifdef相反,其格式如下: \#ifndef 标识符 程序段 1 \#else 程序段 2 \#endif 其意义是,如果未定义标识符,则编译“程序段1”;否则编译“程序段2” 在实际开发中,程序员用\#ifndef来防止头文件被重复包含。 打开/usr/include/stdio.h,第一条有效行的代码是\#ifndef \_STDIO\_H,接下来是\# define \_STDIO\_H 1,最后一行是\#endif。 程序员自定义的头文件,我们也会这么写,如: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 5][] 如果头文件被包含多次,就表示头文件中的函数被多次声明,全局变量被多次定义,在以前的C语言编译器中,这是不允许的,编译时会报错,但是,现在的部分编译器比较智能,多次定义全局变量或多次声明函数也不会报错。这些新的特征让我这个老家伙很不适应。 ## 3、\#undef ## \#undef取消已定义的标识符。 # 版权声明 # C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。 来源:C语言技术网([www.freecplus.net][]) 作者:码农有道 如果这篇文章对您有帮助,请点赞支持,或在您的博客中转发我的文章,谢谢!!! 如果文章有错别字,或者内容有误,或其他的建议或意见,请您留言指正,非常感谢!!! [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70]: /images/20211109/2b67028ba28f4e77b518cd5fb7c417c3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 1]: /images/20211109/e66af0ef0e4b4d1ba7e0896c53764ccc.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 2]: /images/20211109/8a2cdbf667b34f78a412c14db97773a1.png [20190805081706245.png]: /images/20211109/3b52309b482f4ecdb070594e90ee9279.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 3]: /images/20211109/38ae50dee0644f7586ca55b04b1f329a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 4]: /images/20211109/fd959ecfe88242239fc4ae9da9f8209b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1Y3oxMjIxNDA3Mjk_size_16_color_FFFFFF_t_70 5]: /images/20211109/fe4eb657f38d4962a2602374d8f15593.png [www.freecplus.net]: http://www.freecplus.net
相关 【C语言】预处理 文章目录 一、程序环境 1、程序的翻译环境和执行环境 2、编译+链接 1.翻译环境 2.翻译阶段 Love The Way You Lie/ 2024年03月17日 21:32/ 0 赞/ 108 阅读
相关 C语言编译预处理 文章目录 一、预处理指令 二、包含文件 三、宏定义指令 1、无参数的宏 2、带参数的宏 四、条件编译 1、\ 港控/mmm°/ 2023年07月19日 08:10/ 0 赞/ 13 阅读
相关 C语言的预处理和条件编译指令 C语言的预处理和条件编译指令 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM 阳光穿透心脏的1/2处/ 2023年02月20日 12:19/ 0 赞/ 51 阅读
相关 C语言预处理 C语言预处理 预处理 预定义符号 2.宏定义: 自定义一个宏(要符合标识符的命名规则),用于表示任意数据或者表达式. 3.文 秒速五厘米/ 2022年11月25日 13:00/ 0 赞/ 172 阅读
相关 C语言与预处理 C语言与预处理 预处理定义 例子 宏定义说明 \define与\typedef的区别 带参数宏定义 带参宏与带参函数 迈不过友情╰/ 2022年11月06日 14:50/ 0 赞/ 192 阅读
相关 C语言预处理 由源码到可执行的程序 源码-》(编译)-》elf可执行程序 源码-》(编译)-》目标文件.o-》(链接)-》elf可执行程序 源码-》(编译)-》汇编文件.s-》( 女爷i/ 2022年06月02日 07:00/ 0 赞/ 249 阅读
相关 C语言预处理_05 [C语言预处理\_05][C_05] 凡是以 “\”开头的均为预处理命令! 其定义的一般形式为: \define 标示符 字符串 对于宏定义说明以下几点: 桃扇骨/ 2022年03月22日 11:10/ 0 赞/ 304 阅读
相关 C语言编译预处理 C语言由源代码生成可执行程序的过程如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 女爷i/ 2021年11月09日 05:18/ 0 赞/ 404 阅读
还没有评论,来说两句吧...