ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C多文件工程实战:Beej‘s Guide to C的头文件、Makefile与构建系统指南

C多文件工程实战:Beej‘s Guide to C的头文件、Makefile与构建系统指南 C多文件工程实战Beejs Guide to C的头文件、Makefile与构建系统指南【免费下载链接】bgcBeejs Guide to C Programming source项目地址: https://gitcode.com/gh_mirrors/bg/bgcBeejs Guide to CBeejs Guide to C Programming是一本面向初学者的经典 C 语言教程本章带你从零搭建 C 多文件工程如何编写头文件Header File、如何用 gcc 编译对象文件Object File、如何用Makefile管理构建系统实现只重编译改动文件的增量构建。这是一份从第一个#include到第一个make的完整实战指南。为什么 C 程序要拆分成多个文件教程前半部分的小例子通常都能塞进一个.c文件但真实的 C 程序由许多源文件编译后链接成一个可执行文件组成。掌握多文件工程的三件套头文件声明函数原型和共享变量让编译器提前知道跨文件调用对象文件每个.c先编译成.o再统一链接Makefile自动判断哪些文件过期了、只需重编译哪些对应章节在src/bgc_part_1300_multifile.md配套练习在source/exercises/multifile/目录包含 runner.c、total.c、total.h 三个源文件和一份 Makefile。⚠️ 注意上面的仓库链接仅用于 clone文中所有文件路径均相对于仓库根目录。头文件入门让函数跨文件可见最常见的场景函数add()定义在bar.c却要在foo.c里调用。直接gcc -o foo foo.c bar.c编译会报错error: implicit declaration of function add is invalid in C99意思是你在调用一个编译器从未听说过的函数。C 语言要求提前知道函数的返回值和参数类型——这叫函数原型Function Prototype。解决方式是新建一个bar.h头文件只放声明不放实现// bar.h int add(int, int);然后在foo.c里用双引号形式包含它尖括号用于系统头文件双引号用于项目内的头文件#include bar.h从此任何文件想调用add()只需#include bar.h即可不必再手写原型。原理很简单#include会把指定文件原样插入到当前源码的对应位置就像你自己敲进去的一样。防止头文件被重复包含Include Guard头文件里常常会包含其他头文件于是可能出现a.h包含b.h、b.h又包含a.h的死循环编译器会报出类似#include nested depth 200 exceeds maximum的错误。解决办法是头文件保护宏Include Guard——这是写头文件时的固定套路看到就抄#ifndef BAR_H // 如果 BAR_H 没被定义过 #define BAR_H // 定义它 int add(int, int); #endif // 结束保护命名惯例把文件名大写、把点号换成下划线bar.h→BAR_H。这样无论被#include多少次内容实际只生效一次。控制可见性static 与 externextern声明这个变量/函数定义在别的文件里用于跨文件访问全局变量。例如练习中的total.h就用extern int count;让runner.c能看到total.c里定义的count。static加在文件作用域的变量或函数上表示仅限本文件可见即使别的文件用了extern也访问不到。一句话记忆想对外暴露就写进头文件想藏起来就加static。对象文件增量编译的关键 用-ccompile only参数可以把.c编译成对象文件——包含机器码、但还没链接的中间产物gcc -c foo.c # 生成 foo.o gcc -c bar.c # 生成 bar.o gcc -o foo foo.o bar.o # 链接成可执行文件小项目直接gcc -o foo foo.c bar.c一步到位没问题但大项目的关键在于编译很慢、链接很快。假如你有 1000 个 C 文件只改了其中一个那么只需重新编译那一个对象文件再快速链接即可——编译时间骤降。这正是make工具的看家本领它记录每个文件依赖哪些源文件只重建比输出更新的输入。Makefile 实战三步写出自动构建脚本看这份来自官方练习的最小 Makefilesource/exercises/multifile/Makefile.PHONY: clean runner: runner.o total.o gcc -o $ $^ runner.o: runner.c total.h gcc -Wall -Wextra -stdc2x -pedantic -c $ total.o: total.c gcc -Wall -Wextra -stdc2x -pedantic -c $ clean: rm -f runner *.o逐行拆解每条规则的结构都是目标: 依赖 缩进的命令要素含义runner: runner.o total.o最终可执行文件依赖两个对象文件runner.o: runner.c total.h关键点对象文件也依赖头文件total.h一变runner.o自动重编$代表目标文件名这里是runner$^/$代表所有依赖 / 第一个依赖即.c文件.PHONY: clean声明clean是假目标避免与同名文件冲突保存后只需敲make它就替你把上面 5 条 gcc 命令按依赖关系跑完修改total.h再make只会重新编译受影响的部分。构建 Beejs Guide to C 项目本身这个教程项目本身就是一个 C 多文件构建系统的活教材。顶层 Makefile 只有几行核心是引入外部构建系统bgbspd需克隆为同级目录或设置BGBSPD_BUILD_DIR环境变量指向它再include其中的main.make。构建步骤见README.md安装依赖GNU Make、Python 3、Pandoc 2.7.3、XeLaTeXTeX Live、Liberation 字体顶层执行make完成整个指南的编译make stage把构建产物和网站复制到stage目录make clean清理、make pristine还原到初始状态书籍正文按章节拆分为 34 个 Markdown 源文件如src/bgc_part_1300_multifile.md就是本章由src/Makefile中的 Pandoc 流水线统一排版——这与 C 多文件工程多个源文件 → 对象文件 → 链接成品的思想如出一辙。新手自检清单每个.c文件有对应的.h文件吗公共函数原型都放头文件里了吗每个头文件都加了 Include Guard 吗#ifndef/#define/#endif三件套不该暴露的函数加static了吗Makefile 里对象文件依赖了它包含的头文件吗make两次会提示 Nothing to be done 吗如果是说明增量构建配对了 ✅下一步练习打开source/exercises/multifile/运行make然后改一下total.h里的注释再make亲眼看看只有runner.o被重编译——这就是构建系统的全部魔力。【免费下载链接】bgcBeejs Guide to C Programming source项目地址: https://gitcode.com/gh_mirrors/bg/bgc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表