首页 > 编程语言 >菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序

时间:2023-06-09 10:31:43浏览次数:41  
标签:文件 gcc 菜鸟 void 生成 编译 myfile main

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。该目录下是编译程序用到的一些命令行工具,如下图:

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器


Dev-C++ 正是调用这些工具来编译程序的。

复制该目录。在系统的文件管理器地址栏输入控制面板\系统和安全\系统,回车,打开系统设置,如下图:

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器_02

点击高级系统设置,在弹出的对话框中点击环境变量

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译过程_03

在弹出的对话框中,如下图,在系统变量的变量栏下找到Path变量,点击编辑按钮。

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器_04

会再弹出一个对话框,可以看到变量值输入栏中有很多内容,鼠标选中该输入框,将光标移动到输入内容的最后,添加一个英文分号;,然后在后面粘贴之前找到的 gcc 编译器命令行工具目录,我的是C:\Program Files (x86)\Dev-Cpp\MinGW64\bin,然后点确定,依次关闭所有的弹窗。

step2.2:验证

打开开始,输入cmd,回车。打开了控制台终端,输入gcc --version,如果输入如下图所示,则说明设置成功。

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器_05

如果显示错误信息,可能是你前面哪部走错了。或者你需要重启系统。

step3:编辑程序

和前一篇文章一样,我们要编辑三个程序源文件。先创建一个目录,再使用你最喜欢的编辑器创建下面三个文件:

myfile.h

//myfile.h
// 这里只有三个函数声明
void func1();
void func2();
void func3();

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命令跳转到程序所在目录下。

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器_06

编译myfile.c生成中间文件

在 cmd 中输入:

gcc -c myfile.c
  • 1

-c表示只编译成二进制的中间文件,但不链接。你会看到程序所在目录下多了一个myfile.o文件

编译main.c生成中间文件

gcc -c main.c

同样会在当前目录下生成一个 main.o 文件。

链接main.omyfile.o,生成最终的可执行文件:

gcc main.o myfile.o


同样会在目录下生成一个a.exe,即最终的可执行文件。

检测一下a.exe是否能执行:

a.exe

输出如下图所示:

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_源文件_07

说明我们的编译成功了。

你也可以直接使用gcc main.c myfile.c来完成整个过程,这种情况下,编译器还是会在背后走这些步骤,只不过只把最后结果给你看。

在上面的每一步编译过程中,我们都可以用-o参数来指定生成文件的文件名。比如gcc main.o myfile.o -o main.exe生成的可执行文件名为main.exe

C 程序的模块化

C 程序的编译过程

C 程序的编译单位为每个 .c 源文件,整个编译过程大致可以分为四个阶段:预处理、编译、汇编、链接。每个编译单元都会经过预处理、编译,最后将各个单元生成的中间文件链接到一起形成可执行文件。

预处理阶段的工作主要包括:宏替换、头文件包含内容替换等。

编译阶段的主要工作是:将预处理后的源文件转换成汇编代码。

汇编阶段的主要工作是:将上一阶段生成的汇编代码编译成二进制文件,即中间文件。

链接阶段的主要工作是:将各中间文件链接到一起,生成可执行文件。(如果程序使用了静态链接库,链接阶段还会将静态库导入到可执行文件中,目前我们不需要了解。)

上面提到的编译过程不一定完整和准确,但对于我们理解如何编译多个源文件的程序已经够用了。

以前面我们编译的程序为例,我们的整个编译过程如下图所示。

菜鸟攻略–C语言多文件编程初探(二):使用 gcc 手动编译多文件 C 程序_编译器_08


特别提一下,在预处理阶段会进行头文件包含的替换工作。比如将#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.omyfile.o时,“身份ID”就对上了,前者有调用,后者有实现,也就能正确的生成可执行文件了。

C 程序的模块化

其实从前面的编译过程我们就可以直观的知道,不止程序的编写是分模块的,程序的编译过程也是分模块的,各个源文件分开编译后组装。C 程序的编译单元是 .c 文件,每个 .c 源文件都会生成一个 .o 中间文件,最后所有的.o 文件链接成一个可执行文件。只有在最后的链接阶段,.o 文件才会联系到一起。

所以我们修改了某个源文件,只需要重新编译这个源文件即可,没修改的文件不需要重新编译,当然,最后得重新链接一次。假如我们现在修改了myfile.c,我们只想重新生成myfile.o,然后链接myfile.omain.o即可。

所以 C 程序的模块化,即方便了程序员按逻辑组织程序,也减轻了编译器的工作,将每次修改代码后的重编译工作量减到最小。

模块之间的依赖

通过前面对编译过程的分析,我们可以得出这样的结论,main.o依赖于main.cmyfile.hmyfile.o依赖于myfile.cmyfile.h。而a.exe依赖于main.omyfile.o。整个依赖树如下:

a.exe
            |
      -------------
      |           |
    main.o      myfile.o
      |           |
  ---------    -------
  |       |    |     |
main.c  myfile.h  myfile.c

如果某个文件的依赖项改变了,这个文件就得重新生成。myfile.h改变了,main.omyfile.o都得重新生成,进一步a.exe也得重新生成。如果只是myfile.c改变了,myfile.o要重新生成,a.exe也要重新生成。

这个程序十分简单,依赖关系也比较简单,所以我们可以在命令行里手动编译它们,实际上我们是在靠大脑在维护它们的依赖关系。如果程序规模变大,依赖关系将复杂到我们的大脑没办法维护。如果记不住依赖关系,我们一股脑儿的全部重新编译又太耗费时间(大的程序从头编译一次可能会好几个小时,十几个小时,你怕不怕)。这时候我们就得依赖于工具了,工具有半自动和全自动工具。半自动工具,比如 makefile 需要我们手动写一次依赖关系,全自动工具,比如像 VS 和 Dev-C++会全自动维护依赖关系,不需要我们操任何心。我们用 IDE 创建工程时,IDE 在工程目录下创建的那些文件,有一些是中间文件,有一些是用来记录依赖关系的。

结束

恭喜你看到了这里!我们学会了手动编译程序,大致知道了编译器编译程序时做了哪些工作。明白了这些就好,在实际编程时还是使用 IDE 比较方便。我们和其他选手一样用 IDE 编程,但和他们不一样,我们知道 IDE 帮我们做了哪些事,我们简直是看透一切的(男/女)人,哈哈哈~~~



标签:文件,gcc,菜鸟,void,生成,编译,myfile,main
From: https://blog.51cto.com/u_4018548/6445754

相关文章

  • Linux Shell 脚本创建日期文件夹
    mk-time-dir.sh#!/bin/bashdir_name=$(date'+%Y%m%d%H%M')mkdir$dir_nameecho"已创建文件夹${dir_name}"#已创建文件夹202306090936参考:Linuxdate命令......
  • 驱动开发:内核文件读写系列函数
    在应用层下的文件操作只需要调用微软应用层下的API函数及C库标准函数即可,而如果在内核中读写文件则应用层的API显然是无法被使用的,内核层需要使用内核专有API,某些应用层下的API只需要增加Zw开头即可在内核中使用,例如本章要讲解的文件与目录操作相关函数,多数ARK反内核工具都具有对......
  • Linux 通过修改 grub 文件禁用节能模式
    1、执行vi/etc/default/grub命令以编辑该文件 将光标移至GRUB_CMDLINE_LINUX行,在rhgb前新增intel_idle.max_cstate=0intel_pstate=disable字段,输入wq命令,按回车即能保存退出。2、生成启动文件 3、将改动写入镜像 最后执行reboot或者shutdown-rnow命令来......
  • 01-mybatis-快速入门-代理开发、配置文件
    文章目录MybatisMybatis入门案例1、创建User表,添加数据2、创建模块,搭建框架2.1创建模块注意:完善项目目录2.2导入坐标2.3编写MyBatis核心配置文件2.4编写sql映射文件2.5编码3、解决SQL映射文件的警告提示Mapper代理开发1、定义同名接口2、设置namespace并修改核心配置mappe......
  • 02-MyBatis-CRUD-配置文件、参数封装、mybatisX插件、动态sql, 简单的用注解开发
    文章目录MybatisCRUD练习1,配置文件实现CRUD1.1环境准备Debug01:别名mybatisx报错1.2查询所有数据1.2.1编写接口方法1.2.2编写SQL语句1.2.3编写测试方法1.2.4起别名解决上述问题1.2.5使用resultMap解决上述问题1.2.6小结1.3查询详情1.3.1编写接口方法1.3.2编写SQL语句......
  • 【linux】循序渐进学运维-基础篇-文件权限管理
    写在前面:博主是一名投身教培事业的标准八零后,叛逆而且追求自由,昵称取自于苏轼的《水调歌头》中的“高处不胜寒”,时刻提醒自己要耐得住寂寞,受的了孤独,在技术的道路上,不畏艰难,勇往直前。欢迎star,投稿,交流,后续还会有python系列和java系列。文章目录权限的基础概念权限管理命令1)chmod......
  • C语言编程—头文件
    头文件是扩展名为.h的文件,包含了C函数声明和宏定义,被多个源文件中引用共享。有两种类型的头文件:程序员编写的头文件和编译器自带的头文件。在程序中要使用头文件,需要使用C预处理指令#include来引用它。前面我们已经看过stdio.h头文件,它是编译器自带的头文件。引用头文件......
  • 编译安装 gcc 4.9并验证使用
    编译安装gcc4.9并验证使用1.准备环境(GCC编译器)centOS6.3cat/proc/version Linuxversion2.6.32-279.el6.x86_64([email protected])(gccversion4.4.620120305(RedHat4.4.6-4)(GCC))#1SMPFriJun2212:19:21UTC2012gcc--vers......
  • linux下修改文件的拥有者和用户组
    一、使用chown命令更改文件拥有者在shell中,可以使用chown命令来改变文件所有者。chown命令是changeowner(改变拥有者)的缩写。需要要注意的是,用户必须是已经存在系统中的,也就是只能改变为在/etc/passwd这个文件中有记录的用户名称才可以。chown......
  • 【python】多文件编程
    多文件编程在Python中,可以将代码拆分成多个文件进行编程,这样有助于组织和维护大型程序。以下是一些常用的方法:模块导入:将代码划分成几个逻辑上相似的文件,然后使用import语句导入需要使用的模块。包:将相关的模块放到同一个文件夹内,并加上一个名为__init__.py的空文件,这个文件会......