菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序
step1:下载安装 Dev-C++
已经安装了 Dev-C++ 或系统中的可以跳过这步。去官网下载 Dev-C++。我昨天下载,发现有点慢,所以我把安装文件放到百度网盘了,供大家下载,下载链接为:http://pan.baidu.com/s/1pLPenDx。
开始安装,记住安装位置。在安装时只能选择英文,安装完成后,第一次启动时可以选择中文。启动后,关掉。本文中我们不会用到 Dev-C++ 提供的 IDE,我们只用它目录下的 gcc 编译器。
step2:将 Dev-C++ 目录下的 gcc 编译器工具目录添加到系统环境变量
step 2.1:设置系统环境变量
找到 Dev-C++ 的安装目录下的 bin 文件目录。比如我是C:\Program Files (x86)\Dev-Cpp\MinGW64\bin
。该目录下是编译程序用到的一些命令行工具,如下图:
Dev-C++ 正是调用这些工具来编译程序的。
复制该目录。在系统的文件管理器地址栏输入控制面板\系统和安全\系统
,回车,打开系统设置,如下图:
点击高级系统设置
,在弹出的对话框中点击环境变量
在弹出的对话框中,如下图,在系统变量的变量栏下找到Path
变量,点击编辑
按钮。
会再弹出一个对话框,可以看到变量值输入栏中有很多内容,鼠标选中该输入框,将光标移动到输入内容的最后,添加一个英文分号;
,然后在后面粘贴之前找到的 gcc 编译器命令行工具目录,我的是C:\Program Files (x86)\Dev-Cpp\MinGW64\bin
,然后点确定,依次关闭所有的弹窗。
step2.2:验证
打开开始
,输入cmd
,回车。打开了控制台终端,输入gcc --version
,如果输入如下图所示,则说明设置成功。
如果显示错误信息,可能是你前面哪部走错了。或者你需要重启系统。
step3:编辑程序
和前一篇文章一样,我们要编辑三个程序源文件。先创建一个目录,再使用你最喜欢的编辑器创建下面三个文件:
myfile.h
//myfile.h
// 这里只有三个函数声明
void func1();
void func2();
void func3();
- 1
- 2
- 3
- 4
- 5
myfile.c
// myfile.c
// 这里是3个函数实现
#include <stdio.h>
#include "myfile.h"
void func1()
{
printf("func1\n");
}
void func2()
{
printf("func2\n");
}
void func3()
{
printf("func3\n");
}
main.c
# include <stdio.h>
#include "myfile.h"
int main()
{
func1();
func2();
func3();
return 0;
}
step4:编译程序
打开一 cmd 窗口,输入上面三个程序所在的盘符,然后用cd
命令跳转到程序所在目录下。
编译myfile.c
生成中间文件
在 cmd 中输入:
gcc -c myfile.c
- 1
-c
表示只编译成二进制的中间文件,但不链接。你会看到程序所在目录下多了一个myfile.o
文件
编译main.c
生成中间文件
gcc -c main.c
- 1
同样会在当前目录下生成一个 main.o 文件。
链接main.o
和myfile.o
,生成最终的可执行文件:
gcc main.o myfile.o
- 1
同样会在目录下生成一个a.exe
,即最终的可执行文件。
检测一下a.exe
是否能执行:
a.exe
- 1
输出如下图所示:
说明我们的编译成功了。
你也可以直接使用gcc main.c myfile.c
来完成整个过程,这种情况下,编译器还是会在背后走这些步骤,只不过只把最后结果给你看。
在上面的每一步编译过程中,我们都可以用-o
参数来指定生成文件的文件名。比如gcc main.o myfile.o -o main.exe
生成的可执行文件名为main.exe
。
C 程序的模块化
C 程序的编译过程
C 程序的编译单位为每个 .c 源文件,整个编译过程大致可以分为四个阶段:预处理、编译、汇编、链接。每个编译单元都会经过预处理、编译,最后将各个单元生成的中间文件链接到一起形成可执行文件。
预处理阶段的工作主要包括:宏替换、头文件包含内容替换等。
编译阶段的主要工作是:将预处理后的源文件转换成汇编代码。
汇编阶段的主要工作是:将上一阶段生成的汇编代码编译成二进制文件,即中间文件。
链接阶段的主要工作是:将各中间文件链接到一起,生成可执行文件。(如果程序使用了静态链接库,链接阶段还会将静态库导入到可执行文件中,目前我们不需要了解。)
上面提到的编译过程不一定完整和准确,但对于我们理解如何编译多个源文件的程序已经够用了。
以前面我们编译的程序为例,我们的整个编译过程如下图所示。
特别提一下,在预处理阶段会进行头文件包含的替换工作。比如将#include "myfile.h"
替换为myfile.h
文件中的内容。myfile.c
替换后的结果大概如下:
/*
* stdio.h 的替换内容
*/
void func1();
void func2();
void func3();
void func1()
{
printf("func1\n");
}
void func2()
{
printf("func2\n");
}
void func3()
{
printf("func3\n");
}
main.c
替换后的结果也可以这样脑补。
想要前进,我们还得补充一下编译器在编译和链接阶段时所作的工作。我们知道main.o
是从main.c
生成,main.c
中调用了三个函数,而这三个函数在main.c
中并没有实现。那编译器是怎么处理的呢?是这样的:编译器在编译main.c
时看到三个未实现的函数声明,就根据它们的函数声明给它们生成了各自的“身份ID”,不同的函数声明会生成不同的“身份ID”,“身份ID ”是唯一的。编译器暂且将这些“身份ID”记录在中间文件中。在编译myfile.o
时同样会对三个函数生成三个“身份ID”,由于myfile.c
中的函数声明和main.c
中的函数声明一样,所以生成的三个“身份ID”也一样。最后在链接main.o
和myfile.o
时,“身份ID”就对上了,前者有调用,后者有实现,也就能正确的生成可执行文件了。
C 程序的模块化
其实从前面的编译过程我们就可以直观的知道,不止程序的编写是分模块的,程序的编译过程也是分模块的,各个源文件分开编译后组装。C 程序的编译单元是 .c 文件,每个 .c 源文件都会生成一个 .o 中间文件,最后所有的.o 文件链接成一个可执行文件。只有在最后的链接阶段,.o 文件才会联系到一起。
所以我们修改了某个源文件,只需要重新编译这个源文件即可,没修改的文件不需要重新编译,当然,最后得重新链接一次。假如我们现在修改了myfile.c
,我们只想重新生成myfile.o
,然后链接myfile.o
和main.o
即可。
所以 C 程序的模块化,即方便了程序员按逻辑组织程序,也减轻了编译器的工作,将每次修改代码后的重编译工作量减到最小。
模块之间的依赖
通过前面对编译过程的分析,我们可以得出这样的结论,main.o
依赖于main.c
和myfile.h
,myfile.o
依赖于myfile.c
和myfile.h
。而a.exe
依赖于main.o
和myfile.o
。整个依赖树如下:
a.exe
|
-------------
| |
main.o myfile.o
| |
--------- -------
| | | |
main.c myfile.h myfile.c
如果某个文件的依赖项改变了,这个文件就得重新生成。myfile.h
改变了,main.o
和myfile.o
都得重新生成,进一步a.exe
也得重新生成。如果只是myfile.c
改变了,myfile.o
要重新生成,a.exe
也要重新生成。
这个程序十分简单,依赖关系也比较简单,所以我们可以在命令行里手动编译它们,实际上我们是在靠大脑在维护它们的依赖关系。如果程序规模变大,依赖关系将复杂到我们的大脑没办法维护。如果记不住依赖关系,我们一股脑儿的全部重新编译又太耗费时间(大的程序从头编译一次可能会好几个小时,十几个小时,你怕不怕)。这时候我们就得依赖于工具了,工具有半自动和全自动工具。半自动工具,比如 makefile 需要我们手动写一次依赖关系,全自动工具,比如像 VS 和 Dev-C++会全自动维护依赖关系,不需要我们操任何心。我们用 IDE 创建工程时,IDE 在工程目录下创建的那些文件,有一些是中间文件,有一些是用来记录依赖关系的。
结束
恭喜你看到了这里!我们学会了手动编译程序,大致知道了编译器编译程序时做了哪些工作。明白了这些就好,在实际编程时还是使用 IDE 比较方便。我们和其他选手一样用 IDE 编程,但和他们不一样,我们知道 IDE 帮我们做了哪些事,我们简直是看透一切的(男/女)人,哈哈哈~~~
菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序的更多相关文章
- 手动编译Jsp文件
手动模拟Tomcat编译jsp文件 Tomcat编译jsp文件的配置路径是在%tomcat_home%/conf/web.xml中,有这样一段代码 <servlet> <servle ...
- 用csc命令行手动编译cs文件
一般初学c#时,用记事本写代码,然后用命令行执行csc命令行可以编译cs文件.方法有两种 1:配置环境,一劳永逸 一般来说在C:\Windows\Microsoft.NET\Framework\v4. ...
- 如何手动编译java文件
1,在编辑框中,将目录切至java文件所在的地址 如图 2,开始编译java文件 用命令javac 编译目标java文件,文件需带后缀名 ; 用java 执行class, 此时class文件无需带后缀 ...
- 数据攻略●R语言自述
(注明:以下文章均在Linux操作系统下执行) 一.R语言简介 R语言是用于统计分析,图形表示和报告的编程语言和软件环境.R语言由Ross Ihaka和Robert Gentleman在新西兰奥克兰大 ...
- [国嵌攻略][137][DM9000网卡驱动编程]
DM9000数据发送 DM9000数据发送函数是在/drivers/net/dm9000.c中的dm9000_start_xmit函数 static int dm9000_start_xmit(str ...
- Go语言之并发编程(二)
通道(channel) 单纯地将函数并发执行是没有意义的.函数与函数间需要交换数据才能体现并发执行函数的意义.虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 ...
- MinGW(GCC)编译DLL文件
这两天用CB(Code::Blocks)写个小程序,要编译出DLL供VB(6)使用.CB使用mingw-gcc作为编译器,在库文件的产出上跟VC.VS之类的IDE略有不同. 由于C语言的基础知识不是太 ...
- curl库 c语言的curl 编程
c语言的curl 编程 [Linux@centos-64-min exercise]# gcc -Wall -o curltest curltest.c /tmp/ccosVANi.o: In fun ...
- 令牌Token和会话Session原理与攻略
本篇文章将从无到完整的登录框架或API详细讲述登录令牌原理.攻略等安全点. 有些协议或框架也喜欢把令牌叫票据(Ticket),不论是APP还是Web浏览器,很多框架或协议都用到了本文所说的这套类似的认 ...
随机推荐
- C语言:函数
1. int scanf ( char * format [ ,argument, ... ]); 返回被赋值的参数的个数
- .h .cpp区别
首先,我们可以将所有东西都放在一个.cpp文件内. 然后编译器就将这个.cpp编译成.obj,obj是什么东西? 就是编译单元了.一个程序,可以由一个编译单元组成, 也可以有多个编译单元组成. 如果你 ...
- win10 IIS web.config加密不能访问:打不开 RSA 密钥容器
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys 找到密钥文件, 根据时间判断具体是哪一个文件,赋予network service读权限
- 详解Window10下使用IDEA搭建Hadoop开发环境
前言 经过三次重装,查阅无数资料后成功完成hadoop在win10上实现伪分布式集群,以及IDEA开发环境的搭建.一步一步跟着本文操作可以避免无数天坑. 下载安装Hadoop 下载安装包 进入官网下载 ...
- MyEclipse无法打开jsp文件(打开是空白的),但是可以打开java文件
转载: 解决MyEclipse使用时打开JSP发生"An error has occurred,See error log for more details"错误的解决方法这个问题 ...
- RHEL7配置端口转发和地址伪装
说明:这里是Linux服务综合搭建文章的一部分,本文可以作为Linux上使用firewalld做端口转发和地址伪装以及外网访问内网的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭 ...
- WebAssembly正逐渐成为FaaS的主力
相信很多人都知道PaaS(平台即服务)和IaaS(基础设施即服务).而随着云计算时代的发展,逐渐出现了大量的XaaS形式的概念,这些技术从原先的硬件服务器,虚拟化服务,再到容器化逐渐转变.使得软件发布 ...
- java内存模型——重排序
线程安全问题概括来说表现为三个方面:原子性,可见性和有序性. 在多核处理器的环境下:编译器可能改变两个操作的先后顺序:处理器可能不是完全依照程序的目标代码所指定的顺序执行命令:一个处理器执行的多个操作 ...
- C#计算复利方法
复利即是指利滚知利 如存入1000,年利息回0.003,存了答10年,则调用fl(0.003,1000,10); double fl(double rate,double cash,int times ...
- nexus 私服 设置本公司代理 记录
index成功