GCC 详解

 

文章目录

一、GCC是什么

二、Demo

三、GCC的组成部分以及使用到的软件

四、gcc和g++的区别

 


一、GCC是什么

对于 GCC 的认知,很多读者还仅停留在“GCC 是一个C语言编译器”的层面,是很片面的。

谈到 GCC,就不得不提 GNU 计划。GNU 全称 GNU’s Not UNIX,又被称为“革奴计划”,由理查德·斯托曼于 1983 年发起。GNU 计划的最终目标是打造出一套完全自由(即自由使用、自由更改、自由发布)、开源的操作系统,并初步将其命名为 GNU 操作系统(其 logo 如图 1 所示)。

GNU 计划的实施可谓一波三折,最重要的一点是,虽然该计划为 GNU 操作系统量身定做了名为 Thr Hurd 的系统内核,但由于其性能比不上同时期诞生的 Linux 内核,最终 GNU 计划放弃 The Hurd 而选用 Linux 作为 GNU 操作系统的内核。在 Linux 内核的基础上,GNU 计划开发了很多系统部件,GCC 就是其中之一(除此之外,还有 Emacs 等非常实用的软件)。 

由此看来,GNU 计划最终实现了“打造一套自由、开源的操作系统”的初衷,但该操作系统并非完全产自 GNU 计划,因此其被称为 GNU/Linux 操作系统(人们更习惯称为 Linux 操作系统)。

早期 GCC 的全拼为 GNU C Compiler,即 GUN 计划诞生的 C 语言编译器,显然最初 GCC 的定位确实只用于编译 C 语言。但经过这些年不断的迭代,GCC 的功能得到了很大的扩展,它不仅可以用来编译 C 语言程序,还可以处理 C++、Go、Objective -C 等多种编译语言编写的程序。与此同时,由于之前的 GNU C Compiler 已经无法完美诠释 GCC 的含义,所以其英文全称被重新定义为  GNU Compiler Collection,即 GNU 编译器套件

所谓编译器,可以简单地将其理解为“翻译器”。要知道,计算机只认识二进制指令(仅有 0 和 1 组成的指令),我们日常编写的 C 语言代码、C++ 代码、Go 代码等,计算机根本无法识别,只有将程序中的每条语句翻译成对应的二进制指令,计算机才能执行。

GCC 编译器从而停止过改进。截止到今日(2020 年 5 月),GCC 已经从最初的 1.0 版本发展到了 10.1 版本,期间历经了上百个版本的迭代。作为一款最受欢迎的编译器,GCC 被移植到数以千计的硬件/软件平台上,几乎所有的 Linux 发行版也都默认安装有 GCC 编译器。

表1:GCC 支持的硬件平台(部分)
硬件 操作系统
Alpha Red Hat Linux 7.1
HPPA HPUX 11.0
Intel x86 Debian Linux 2.2、Red Hat Linux 6.2 和 FreeBSD 4.5
MIPS IRIX 6.5
PowerPC AIX 4.3.3
Sparc Solaris 2.7

 值得一提的是,原汁原味的 GCC 编译器没有我们熟悉的界面窗口,要想使用它,必须编写对应的 gcc 命令。所谓原汁原味,指的是纯 GCC 编译器和集成了 GCC 编译器的开发软件(IDE),和前者相比,后者在集成 GCC 编译器功能的同时,还向用户提供了友好的界面窗口,使得用户即便记不住 gcc 命令,也能从事开发工作,这极大地降低了用户的学习成本。

我们知道,操作系统大致分为 2 大阵营,分别是 Windows 阵营和类 Unix 阵营(包括 Unix、Linux、Mac OS、安卓等)。通常情况下,Windows 系统下用户更习惯使用现有的 IDE 来编译程序;而类 Unix 系统下,用户更喜欢直接编写相应的 gcc 命令来编译程序。


 

二、Demo

在了解什么是 GCC 编译器的基础上,这里以在 CentOS 操作系统(Linux 发行版之一)上使用 gcc 命令运行 C 语言程序为例,让读者更直观的感受一下 GCC 编译器的功能和使用方法。

 

对于此程序,我们可以使用如下的 gcc 命令:

下图演示了如何使用 gcc 命令将 C 语言代码编译成一个可执行文件:

如图 2 所示,通过编写对应的 gcc 命令并执行,就可以轻松将我们编写的程序编译成一个二进制可执行文件。


三、GCC的组成部分以及使用到的软件

GCC 是由许多组件组成的。表 1 列出了 GCC 的各个部分,但它们也并不总是出现 的。有些部分是和语言相关的,所以如果没有安装某种特定语言,系统中就不会出现相关的文件。

表1:GCC 安装的各个部分
部分 描述
c++ gcc 的一个版木,默认语言设置为 C++,而且在连接的时候自动包含标准 C++ 库。这和 g++ 一样
ccl 实际的C编译程序
cclplus 实际的 C++ 编泽程序
collect2 在不使用 GNU 连接程序的系统上,有必要运行 collect2 来产生特定的全局初始化代码(例如 C++ 的构造函数和析构函数)
configure GCC 源代码树根目录中的一个脚木。用于设置配置值和创建GCC 编译程序必需的 make 程序的描述文件
crt0.o 这个初始化和结束代码是为每个系统定制的,而且也被编译进该文件,该文件然后会被连接到每个可执行文件中来执行必要的启动和终止程序
cygwin1.dll Windows 的共享库提供的 API,模拟 UNIX 系统调用
f77 该驱动程序可用于编译 Fortran
f771 实际的 Fortran 编译程序
g++ gcc 的一个版木,默认语言设置为 C++,而且在连接的时候自动包含标准 C++ 库。这和 c++ 一样
gcc 该驱动程序等同于执行编译程序和连接程序以产生需要的输出
gcj 该驱动程序用于编译 Java
gnat1 实际的 Ada 编译程序
gnatbind 一种工具,用于执行 Ada 语言绑定
gnatlink 一种工具,用于执行 Ada 语言连接
jc1 实际的 Java 编译程序
libgcc 该库包含的例程被作为编泽程序的一部分,是因为它们可被连接到实际的可执行程序中。 它们是特殊的例程,连接到可执行程序,来执行基木的任务,例如浮点运算。这些库中的例程通常都是平台相关的
libgcj 运行时库包含所有的核心 Java 类
libobjc 对所有 Objective-C 程序都必须的运行时库
libstdc++ 运行时库,包括定义为标准语言一部分的所有的 C++ 类和函数

表 2 列出的软件和 GCC 协同工作,目的是实现编译过程。有些是很基本的(例如 as 和 Id),而其他一些则是非常有用但不是严格需要的。尽管这些工具中的很多都是各种 UNIX 系统的本地工具,但还是能够通过 GNU 包 binutils 得到大多数工具。

表2:GCC 使用的软件工具
工具 描述
addr2line
ar 这是一个程序,可通过从文档中增加、删除和析取文件来维护库文件。通常使用该工具是为了创建和管理连接程序使用的目标库文档。该程序是 binutils 包的一部分
as GNU 汇编器。实际上它是一族汇编器,因为它可以被编泽或能够在各种不同平台上工作。 该程序是 binutils 包的一部分
autoconf 产生的 shell 脚木自动配置源代码包去编泽某个特定版木的 UNIX
c++filt 程序接受被 C++ 编泽程序转换过的名字(不是被重载的),而且将该名字翻泽成初始形式。 该程序是 binutils 包的一部分
f2c 是 Fortran 到C的翻译程序。不是 GCC 的一部分
gcov gprof 使用的配置工具,用来确定程序运行的时候哪一部分耗时最大
gdb GNU 调试器,可用于检查程序运行时的值和行为
GNATS GNU 的调试跟踪系统(GNU Bug Tracking System)。一个跟踪 GCC 和其他 GNU 软件问题的在线系统
gprof 该程序会监督编泽程序的执行过程,并 告程序中各个函数的运行时间,可以根据所提供 的配置文件来优化程序。该程序是 binutils 包的一部分
ld GNU 连接程序。该程序将目标文件的集合组合成可执行程序。该程序是 binutils 包的一部
libtool 一个基本库,支持 make 程序的描述文件使用的简化共享库用法的脚木
make 一个工具程序,它会读 makefile 脚木来确定程序中的哪个部分需要编泽和连接,然后发布 必要的命令。它读出的脚木(叫做 makefile 或 Makefile)定义了文件关系和依赖关系
nlmconv 将可重定位的目标文件转换成 NetWare 可加载模块(NetWare Loadable Module, NLM)。该 程序是 binutils 的一部分
nm 列出目标文件中定义的符 。该程序是 binutils 包的一部分
objcopy 将目标文件从一种二进制格式复制和翻译到另外一种。该程序是 binutils 包的一部分
objdump 显示一个或多个目标文件中保存的多种不同信息。该程序是 binutils 包的一部分
ranlib 创建和添加到 ar 文档的索引。该索引被 Id 使用来定位库中的模块。该程序是 binutils 包的一部分
ratfor Ratfor 预处理程序可由 GCC 激活,但不是标准 GCC 发布版的一部分
readelf 从 ELF 格式的目标文件显示信息。该程序是 binutils 包的一部分
size 列出目标文件中每个部分的名字和尺寸。该程序是 binutils 包的一部分
strings 浏览所有类型的文件,析取出用于显示的字符串。该程序是 binutils 包的一部分
strip 从目标文件或文档库中去掉符 表,以及其他调试所需的信息。该程序是 binutils 包的一部
vcg Ratfor 浏览器从文木文件中读取信息,并以图表形式显示它们。而 vcg 工具并不是 GCC 发布中的一部分,但 -dv 选项可被用来产生 vcg 可以理解的优化数据的格式
windres Window 资源文件编泽程序。该程序是 binutils 包的一部分

 


四、gcc和g++的区别

发展至今(2020 年 6 月份),GCC 编译器已经更新至 10.1.0 版本,其功能也由最初仅能编译 C 语言,扩增至可以编译多种编程语言,其中就包括 C++ 。

除此之外,当下的 GCC 编译器还支持编译 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程序,甚至于 GCC 6 以及之前的版本还支持编译 Java 程序。但本教程主要讲解如何使用 GCC 编译器编译运行 C 和 C++ 程序,因此有关其它编程语言如何使用 GCC 编译器编译,将不再做具体讲解。

值得一提的是,实际使用中我们更习惯使用 gcc 指令编译 C 语言程序,用 g++ 指令编译 C++ 代码。需要强调的一点是,这并不是 gcc 和 g++ 的区别,gcc 指令也可以用来编译 C++ 程序,同样 g++ 指令也可以用于编译 C 语言程序。

那么,gcc 和 g++ 的区别是什么呢p>

实际上,只要是 GCC 支持编译的程序代码,都可以使用 gcc 命令完成编译。可以这样理解,gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别,比如:

  • xxx.c:默认以编译 C 语言程序的方式编译此文件;
  • xxx.cpp:默认以编译 C++ 程序的方式编译此文件。
  • xxx.m:默认以编译 Objective-C 程序的方式编译此文件;
  • xxx.go:默认以编译 Go 语言程序的方式编译此文件;

当然,gcc 指令也为用户提供了“手动指定代表编译方式”的接口,即使用 -x 选项。例如,gcc -xc xxx 表示以编译 C 语言代码的方式编译 xxx 文件;而 gcc -xc++ xxx 则表示以编译 C++ 代码的方式编译 xxx 文件。

但如果使用 g++ 指令,则无论目标文件的后缀名是什么,该指令都一律按照编译 C++ 代码的方式编译该文件。也就是说,对于 .c 文件来说,gcc 指令以 C 语言代码对待,而 g++ 指令会以 C++ 代码对待。但对于 .cpp 文件来说,gcc 和 g++ 都会以 C++ 代码的方式编译。

有读者可能会认为,C++ 兼容 C 语言,因此对于 C 语言程序来说,使用 gcc 编译还是使用 g++ 编译,应该没有什么区别,事实并非如此。严格来说,C++ 标准和 C 语言标准的语法要求是有区别的。举个例子:

如上所示,这是一段不规范的 C 语言代码。如果我们使用 gcc 指令编译,如下所示:

可以看到,该指令的执行过程并没有发生任何错误。而同样的程序,如果我们使用 g++ 指令编译:

可以看到,GCC 编译器发现了 3 处错误。显然,C++ 标准对代码书写规范的要求更加严格。

除此之外对于编译执行 C++ 程序,使用 gcc 和 g++ 也是有区别的。要知道,很多 C++ 程序都会调用某些标准库中现有的函数或者类对象,而单纯的 gcc 命令是无法自动链接这些标准库文件的。举个例子:

可以看到,整个编译过程没有 任何错误。但如果使用 gcc 指令:

读者可自行编译,就可以看到很多 错信息。其根本原因就在于,该程序中使用了标准库 提供的类对象,而 gcc 默认是无法找到它们的。

如果想使用 gcc 指令来编译执行 C++ 程序,需要在使用 gcc 指令时,手动为其添加 -lstdc++ -shared-libgcc 选项,表示 gcc 在编译 C++ 程序时可以链接必要的 C++ 标准库。也就是说,我们可以这样编译 demo.cpp 文件:

由此,demo.cpp 就被成功的编译了。

读者可以这样认为,g++ 指令就等同于指令。显然后者书写是非常麻烦的,大多数人会更喜欢前者。

对于 gcc 和 g++ 指令,还有其它更多细节方面的区别。读者只需要知道,对于 C 语言程序的编译,我们应该使用 gcc 指令,而编译 C++ 程序则推荐使用 g++ 指令,这就足够了。


 

参考:http://c.biancheng.net/view/7930.html

 

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年8月13日
下一篇 2020年8月13日

相关推荐