news 2026/5/12 15:39:06

快速学C语言——第16章:预处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
快速学C语言——第16章:预处理

第16章:预处理

​ 在C语言程序的编译过程中,有一个特殊的阶段发生在实际编译之前,这就是预处理阶段

​ 预处理器是一个独立的程序,它处理源代码中以#开头的特殊指令,为后续的编译工作做准备。

​ 理解预处理是掌握C语言编译流程的重要一环,它能帮助我们编写更灵活、更可移植的代码。


16.1 预处理概述

编译流程

​ ①预处理:处理所有预处理指令,生成纯粹的C代码。

​ ②编译:将C代码翻译成汇编代码。

​ ③汇编:将汇编代码转换成机器代码(目标文件)。

​ ④链接:将多个目标文件和库文件连接成可执行文件。

​ 预处理器不关心C语言的语法规则,它只是进行简单的文本替换和处理工作。


16.2 宏定义:#define

​ #define是最常用的预处理指令,用于创建宏。

16.2.1 对象式宏

对象式宏用于定义常量简单的文本替换

#include<stdio.h>// 定义常量宏。#definePI3.14159#defineMAX_SIZE100#definePROGRAM_NAME"我的程序"// 定义字符串宏。#defineWELCOME_MESSAGE"欢迎使用C语言"intmain(){doubleradius=5.0;doublearea=PI*radius*radius;printf("%s\n",PROGRAM_NAME);printf("%s\n",WELCOME_MESSAGE);printf("半径为%.2f的圆面积:%.2f\n",radius,area);printf("最大尺寸:%d\n",MAX_SIZE);return0;}

运行结果:

我的程序 欢迎使用C语言 半径为5.00的圆面积:78.54 最大尺寸:100 -------------------------------- Process exited after0.05483seconds withreturnvalue0请按任意键继续...

#define的格式是#define A B预处理器会把代码中出现的A全部替换成B。上述例子中printf("%s\n", PROGRAM_NAME);直接输出的"我的程序"PROGRAM_NAME"我的程序"等价。

16.2.2 函数式宏

​ 函数式宏可以接受参数,看起来像函数调用,但实际上是文本替换。

#include<stdio.h>// 函数式宏定义。#defineSQUARE(x)((x)*(x))#defineMAX(a,b)((a)>(b)?(a):(b))#defineMIN(a,b)((a)<(b)?(a):(b))#definePRINT_INT(n)printf(#n" = %d\n",n)intmain(){intx=5,y=10;printf("%d的平方是:%d\n",x,SQUARE(x));printf("%d和%d中较大的数是:%d\n",x,y,MAX(x,y));printf("%d和%d中较小的数是:%d\n",x,y,MIN(x,y));PRINT_INT(x);// 输出:x = 5。PRINT_INT(y);// 输出:y = 10。return0;}

运行结果:

5的平方是:255和10中较大的数是:105和10中较小的数是:5 x=5y=10-------------------------------- Process exited after0.05414seconds withreturnvalue0请按任意键继续...

​ 重要提示:在定义函数式宏时,参数和整个表达式都应该用括号包围,以避免运算符优先级问题。


16.3 文件包含:#include

​ #include用于将其他文件的内容插入到当前文件中

// 系统头文件 - 使用尖括号。#include<stdio.h>#include<stdlib.h>#include<string.h>// 自定义头文件 - 使用双引号。#include"my_functions.h"#include"config.h"

创建和使用自定义头文件

my_functions.h

#ifndefMY_FUNCTIONS_H// 头文件保护,防止重复包含。#defineMY_FUNCTIONS_H// 函数声明。intadd(inta,intb);intmultiply(inta,intb);voidprint_message(constchar*message);// 常量定义。#defineMAX_VALUE1000#defineMIN_VALUE0#endif

my_functions.c

#include"my_functions.h"//导入自定义头文件。#include<stdio.h>// 函数实现。intadd(inta,intb){returna+b;}intmultiply(inta,intb){returna*b;}voidprint_message(constchar*message){printf("消息:%s\n",message);}

main.c

#include<stdio.h>#include"my_functions.h"intmain(){intresult1=add(10,20);intresult2=multiply(5,6);printf("10 + 20 = %d\n",result1);printf("5 * 6 = %d\n",result2);print_message("Hello from header file!");printf("最大值:%d\n",MAX_VALUE);return0;}

16.4 条件编译

​ 条件编译允许我们根据不同的条件编译不同的代码段

16.4.1 #if, #elif, #else, #endif
#include<stdio.h>#defineDEBUG_LEVEL2#defineVERSION3intmain(){// 根据DEBUG_LEVEL编译不同的调试代码。#ifDEBUG_LEVEL>=2printf("[DEBUG] 程序开始执行\n");#endif#ifVERSION==1printf("版本1的功能\n");#elifVERSION==2printf("版本2的功能\n");#elifVERSION==3printf("版本3的功能\n");#elseprintf("未知版本\n");#endif#ifDEBUG_LEVEL>=1printf("[DEBUG] 程序执行完成\n");#endifreturn0;}

运行结果:

[DEBUG]程序开始执行 版本3的功能[DEBUG]程序执行完成 -------------------------------- Process exited after0.01537seconds withreturnvalue0请按任意键继续...
16.4.2 #ifdef和#ifndef
#include<stdio.h>// 在编译时定义:gcc -DDEBUG program.c// #define DEBUGintmain(){#ifdefDEBUGprintf("[调试模式] 开始执行调试代码\n");// 调试专用的代码。printf("[调试模式] 变量检查完成\n");#elseprintf("正常执行模式\n");#endif#ifndefRELEASEprintf("这不是发布版本\n");#endifreturn0;}

运行结果:

正常执行模式 这不是发布版本 -------------------------------- Process exited after0.06809seconds withreturnvalue0请按任意键继续...

​ 如果定义了DEBUG, 执行 调试专用的代码。

16.4.3 实际应用:跨平台代码
#include<stdio.h>// 根据平台定义不同的功能。#ifdef_WIN32#definePLATFORM"Windows"#defineCLEAR_SCREEN"cls"#elifdefined(__linux__)#definePLATFORM"Linux"#defineCLEAR_SCREEN"clear"#elifdefined(__APPLE__)#definePLATFORM"macOS"#defineCLEAR_SCREEN"clear"#else#definePLATFORM"未知平台"#defineCLEAR_SCREEN"echo '清屏命令未定义'"#endifintmain(){printf("当前运行平台:%s\n",PLATFORM);// 在实际项目中,可以使用 system(CLEAR_SCREEN) 来清屏printf("清屏命令:%s\n",CLEAR_SCREEN);return0;}

16.5 其他预处理指令

16.5.1 #undef - 取消宏定义
#include<stdio.h>#defineTEMP_VALUE100intmain(){printf("TEMP_VALUE = %d\n",TEMP_VALUE);#undefTEMP_VALUE// 取消宏定义。// printf("TEMP_VALUE = %d\n", TEMP_VALUE); // 错误!TEMP_VALUE未定义。#defineTEMP_VALUE200// 重新定义。printf("重新定义后 TEMP_VALUE = %d\n",TEMP_VALUE);return0;}
16.5.2 #error - 生成编译错误
#include<stdio.h>// 检查必要的定义。#ifndefREQUIRED_CONFIG#error"REQUIRED_CONFIG 必须被定义!"#endif// 检查编译器版本。#if__STDC_VERSION__<201112L#error"需要C11或更高版本的编译器"#endifintmain(){printf("程序正常执行\n");return0;}
16.5.3 #pragma - 编译器特定指令
#include<stdio.h>// 禁止特定警告(编译器相关)。#pragmaGCC diagnostic ignored"-Wunused-variable"// 打包结构体,节省内存。#pragmapack(push,1)// 按1字节对齐structPackedData{chara;intb;charc;};#pragmapack(pop)// 恢复默认对齐// 默认对齐的结构体。structNormalData{chara;intb;charc;};intmain(){printf("打包结构体大小:%zu字节\n",sizeof(structPackedData));printf("普通结构体大小:%zu字节\n",sizeof(structNormalData));return0;}

16.6 预定义宏

C语言预定义了一些有用的宏,它们提供关于编译环境的信息。

#include<stdio.h>intmain(){printf("文件名:%s\n",__FILE__);// 当前文件名printf("行号:%d\n",__LINE__);// 当前行号printf("编译日期:%s\n",__DATE__);// 编译日期printf("编译时间:%s\n",__TIME__);// 编译时间// C标准版本检测#ifdef__STDC_VERSION__printf("C标准版本:%ld\n",__STDC_VERSION__);#endif#ifdef__cplusplusprintf("这是C++代码\n");#elseprintf("这是C代码\n");#endifreturn0;}

16.7 预处理运算符

16.7.1 #运算符:字符串化

#运算符将宏参数转换为字符串常量。

#include<stdio.h>#defineSTRINGIFY(x)#x#definePRINT_VAR(var)printf(#var" = %d\n",var)intmain(){intmy_variable=42;printf(STRINGIFY(Hello World!\n));// 输出:Hello World!PRINT_VAR(my_variable);// 输出:my_variable = 42// 多级字符串化#defineLEVEL1(x)#x#defineLEVEL2(x)LEVEL1(x)intvalue=100;printf(LEVEL1(value));// 输出:valueprintf(LEVEL2(value));// 输出:100return0;}
16.7.2 ##运算符:标记连接

##运算符用于连接两个标记。

#include<stdio.h>#defineCONCAT(a,b)a##b#defineMAKE_VARIABLE(name,number)name##numberintmain(){intxy=100;printf("CONCAT(x, y)的值:%d\n",CONCAT(x,y));// 输出:100intvar1=10,var2=20,var3=30;intMAKE_VARIABLE(var,1)=100;// 创建变量var1intMAKE_VARIABLE(var,2)=200;// 创建变量var2printf("var1 = %d\n",var1);// 输出:100(不是10!)printf("var2 = %d\n",var2);// 输出:200(不是20!)return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 15:38:08

开源ChatGPT-Web项目部署指南:零成本搭建AI对话助手

1. 项目概述&#xff1a;一个能让你“白嫖”ChatGPT的Web界面如果你和我一样&#xff0c;对ChatGPT的强大能力垂涎三尺&#xff0c;但又对高昂的API费用或者繁琐的注册流程望而却步&#xff0c;那么你肯定会对“Niek/chatgpt-web”这个项目感兴趣。这本质上是一个开源项目&…

作者头像 李华
网站建设 2026/5/12 15:37:19

从图文到视频:用 Python 打造公众号文章自动化转视频号的爆款流水线

摘要:本文详解一套完全基于开源工具(Python + edge-tts + ffmpeg)的自动化系统,可将任意微信公众号文章一键转换为横屏/竖屏视频,直接用于视频号分发。全程无需剪辑软件、无需出镜、无需复杂配置,5 分钟部署,1 条命令生成专业级视频。 🔥 为什么你需要这个? 在 AIGC…

作者头像 李华
网站建设 2026/5/12 15:35:41

ComfyUI-FramePackWrapper终极指南:8GB显存实现高质量AI视频生成

ComfyUI-FramePackWrapper终极指南&#xff1a;8GB显存实现高质量AI视频生成 【免费下载链接】ComfyUI-FramePackWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-FramePackWrapper 想要在有限硬件条件下实现专业级AI视频生成吗&#xff1f;ComfyUI-Fram…

作者头像 李华
网站建设 2026/5/12 15:35:39

从呼吸检测糖尿病看气体传感器与医疗电子的工程化挑战

1. 项目概述&#xff1a;从“扎手指”到“吹口气”的糖尿病检测革命 作为一名长期关注医疗电子与传感器技术交叉领域的工程师&#xff0c;我对那些能将复杂医学诊断“傻瓜化”、“无创化”的创新总是充满兴趣。今天想和大家深入聊聊一个十多年前就让我眼前一亮的构想&#xff1…

作者头像 李华
网站建设 2026/5/12 15:35:38

工程师视角:用EDA思维与Python建模解析超级月亮光学现象

1. 项目概述&#xff1a;从“超级月亮”的观察&#xff0c;到工程师的思维实验 昨晚&#xff0c;确切地说是凌晨一点&#xff0c;我和妻子关掉了屋外所有的灯&#xff0c;站在后院。头顶上那轮所谓的“超级月亮”正散发着惊人的光芒&#xff0c;亮到足以清晰地勾勒出花园里每一…

作者头像 李华
网站建设 2026/5/12 15:35:19

数字时代的计划性抹杀:从强制升级到生态锁定的技术围剿

1. 数字时代的“计划性报废”&#xff1a;从凯迪拉克到小电驴的隐喻 前几天&#xff0c;我在网上申请一张信用卡&#xff0c;过程堪称一场荒诞剧。银行明明通过邮件联系我&#xff0c;也知道我的账号密码&#xff0c;甚至在我通过了“我不是机器人”的图片验证后&#xff0c;却…

作者头像 李华