【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

这篇具有很好参考价值的文章主要介绍了【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:Linux
🎯长路漫漫浩浩,万事皆有期待

上一篇博客:【Linux】Linux环境基础工具的基本使用及配置(yum、vim)

前言

在上一篇 Linux 博客中,我们讲解了 vim 编辑器的使用,可以在 Linux 上写代码了。但是写的代码如何编译?

在 Linux 中,C 语言用 gcc 编译;C++ 用 g++ 编译。

gcc 演示翻译环境

对于一个 C 程序,从源文件到形成可执行程序一共要进行四步:预处理、编译、汇编、链接 。这四步过程被称为 翻译环境 。

接下来,我们用 gcc 分别演示这四个过程。

1、预处理

在预处理中,需要完成头文件的展开、宏替换、去注释、条件编译等工作。

经过预处理后,当前文件还是 C 语言,只不过变得更加精简。

预处理指令 :

gcc -E file.c -o file.i

-E 选项:让 gcc 进行程序的预处理,预处理之后就停下来。
-o 选项:-o 选项紧跟目标生成文件的名称。gcc -o file.i file.c 或者上方的指令都是可以的。

样例程序 :

#include <stdio.h>

#define FOO // #define 后定义内容可为空
#define MAX 100

int main()
{
    int max = MAX;
    printf("%d\n", max);

    printf("hello vim!\n");
    printf("hello vim!\n");
    //printf("hello vim!\n");
   //printf("hello vim!\n");
    printf("hello vim!\n");
    printf("hello vim!\n");

    #ifdef FOO 
    printf("yes");
    #else
    printf("no");
    #endif

    return 0;
}

进行预处理 :

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

预处理之后生成 file.i 文件,分别打开 .c 和 .i 文件进行对比 :

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

我们发现代码变为八百多行,这是因为头文件 #include <stdio.h> 被展开,同时预处理的其他过程也都进行了。

2、编译

当程序在编译时,gcc 会检查代码是否有语法错误,了解代码基本内容,检查无误就会把代码翻译为汇编语言

汇编语言中包含源文件的部分内容,所以也可以说该文件为 C 语言汇编代码 。

编译指令 :

gcc -S file.i -o file.s

-S 选项:让 gcc 进行程序的编译,编译之后就停下来。
-o 选项的位置可以改变,但是一定要记住 -o 选项的规则。
.s :生成汇编代码的后缀

通过源文件 .c 也可以形成编译后的文件,指令为 gcc -s file.c -o file.s,但是我们为了演示过程的连续性,我们统一从上次生成的文件开始执行指令。

进行编译 :

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

观察 file.s 文件内容:

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

上部分框起来的语句含有 c 语言的样子;而下部分框起来的语句则是汇编代码,由此证明在编译过后生成的文件为 C 语言汇编代码。

3、汇编

汇编之后会把汇编语言转换为二进制文件。

这里的二进制文件可以说是 可重定位二进制文件 。该文件不能被执行,类似于 windows 上的 .obj 文件。

这一步把我们自己的代码翻译为二进制目标文件

由于机器只认识二进制文件,所以这一步就是把人能看懂的文件,翻译成机器能看懂的,就是 生成机器可识别代码

汇编指令 :

gcc -c file.s -o test.o

-c 选项:让 gcc 进行程序的汇编,汇编之后就停下来。
.o :生成二进制文件的后缀。

进行汇编 :

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

file.o 内容:
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

打开文件发现什么都看不懂。

这就是二进制文件,计算机可以识别该文件。

那么该文件可以执行吗?

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

不可以执行,报错信息为权限被拒绝,通常为权限不够。那这怎么证明该文件不能执行?

我们将其提权试试:

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

然后再次 ./file.o 执行该文件:

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

仍然执行失败,并报错:无法执行该二进制文件。所以这就证明结论:汇编生成的二进制文件不可执行!

4、链接

链接过程就是将程序和对应的库链接起来,编译器会自动识别语言。

链接指令 :

gcc file.o -o myfile

生成文件为可执行程序
gcc file.o 也可以完成链接

进行链接 :

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

再执行生成的可执行程序 test :
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
总结:链接后的可执行文件才可以执行。

总结

我们将翻译过程按步执行是为了理解程序由源代码到可执行程序的一个过程。

实际上,在我们日常编译代码只需要 gcc file.c 就可以一步生成可执行文件

快速记忆方式:
对于 预处理、编译、汇编 三步的选项分别为 ESc ,可以与键盘上的 esc 键来帮助记忆,区别前两个字母是大写。而生成的文件后缀分别为 iso 可以利用镜像文件(ISO)来记忆。

动静态链接库

1、库的认识

首先清楚一点,我们写的代码里面经常会用库函数,这些调用接口的方式是我们写的,但是这些库函数的底层实现不是我们写的,而这中间就有一个调用库的过程。

在链接的过程中,需要对形成的二进制文件和库文件进行合并从而形成可执行程序,这边就调用了库。库是能成功编译的必要条件。
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
我们一直在使用库,至少是语言上的库。

比如上方链接生成的可执行程序 test ,它就依赖了库。

通过 ldd test ,就可以查看该程序依赖了哪些库:

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

不仅程序依赖库,我们在 linux 下能进行代码编写也是因为内置了库。linux 默认有语言级别的头文件,和语言对应的库。

通过 ls /usr/include/ 就可以看到系统的内置的头文件,我们通过头文件就可以根据库函数,找到对应的方法,从而链接到正确的库:

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

在linux 下,库分两种 :

静态库,格式为 libXXX.a 。
动态库,格式为 libXXX.so 。
XXX为库名

基于上面的格式,不同的库还可能会有版本,例如 test 程序就依赖了libc.so.6 ,后面的 .6 就是版本:
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

并且我们发现可执行程序依赖的就是 .so 动态库。(图中的/lib64/libc.so.6就是当前云服务器当中的C标准库)

linux 上特有的后缀划分:
对于动静态库,以lib 为前缀,.a/.so 为后缀,掐头去尾就是名称。例如 libc.so.6 ,它的名字就是 c ,是 c 语言内置库。

windows 上特有的后缀划分:静态库为 lib ,动态库为 dll 。

不止可执行程序,就连指令也依赖于库,我们观察几个指令:(我们可以使用ldd指令查看动态链接的可执行文件所依赖的库)
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

常用的 ls, tar 它们都依赖于库,甚至还依赖于 c 库。

由此发现,指令和 c 程序一样,都依赖与库。所以我们可以将指令看待为:指令是程序,是工具。

虽然从编译角度来说,指令和我们写的 c 程序没有任何区别,但是从功能上来说确是天差地别。

总结:库是必要的,并且库分为动态库和静态库 。

2、链接方式

Linux 的链接方式就两种:

动态链接
静态链接

而 Linux 默认的链接方式为 动态链接 ,我们来证明一下:

用 file 指令查看 test 文件的类型:
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

我们发现生成的可执行程序默认就是采用的 动态链接 。

那么为什么采用动态链接而不采用静态链接?这里面有什么原因?

我们先了解一下动静态库。

3、动态库与静态库

动态库对应的链接方式为动态链接;静态库对应的链接方式为静态链接。

动态链接必须使用动态库,静态链接必须使用静态库。

动态库优缺点:

动态库也可以说是共享库。动态库在链接的时候,并没有把相应的库文件加载到可执行程序中,而是在运行的时候,拷贝库中所需代码的地址到可执行程序中相关的位置。
通过这种链接方式,使用动态库就大大节省了内存损耗
但是这也带来一个缺点,由于动态库链接时,是通过地址链接的。所以只要我们的动态库缺失,程序便无法运行

静态库优缺点:

静态库则是在编译链接时,把库文件的代码全部加载到可执行程序中。
这种链接方式导致生成文件体积庞大。若文件数目一多,到时候内存就会被占用很多。
但是这也有一个优点,这样就使得程序不依赖于库了。即使库出了问题,也没事,因为我们已经将代码加载到程序中了。

通过上面,我们发现,动态库可以大大节省内存开销,并且一般对应的动态库并不会出问题,再衡量可执行程序很多的情况,动态链接其实是最好的链接方式。

所以 Linux 默认是采用动态链接的链接方式。

4、两种链接方式的使用

对于动态链接,我们已经使用过了,比如上文生成的 test 文件,就是动态链接生成的。

而静态链接则需要通过特定方式来使用,并且 Linux 默认只装了动态库,静态库是没装的,所以先安装一下:
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
C语言静态库:

sudo yum install -y glibc-static

C++静态库:

sudo yum install -y libstdc++-static

安装完毕后,就可以使用了。

静态链接的使用方式为:

gcc -o file.c -o file-static -static

-o 后面还是自定义名称,这里只是为了做区别
结尾的 -static 代表以静态链接方式编译

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

我们发现,静态链接后生成的可执行程序的体积非常大。

再用 file file-static 查看一下文件类型:
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

就变成 statically linked:静态链接了。

5、debug和release

程序发布方式:
 1、debug版本:程序本身会被加入更多的调试信息,以便于进行调试。
 2、release版本:不会添加任何调试信息,是不可调试的。

在Linux当中gcc/g++默认生成的可执行程序是release版本的,是不可被调试的。如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g选项。
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

对同一份源代码分别生成其release版本和debug版本的可执行程序,并通过ll指令可以看到,debug版本发布的可执行程序的大小比release版本发布的可执行程序的大小要大一点,其原因就是以debug版本发布的可执行程序当中包含了更多的调试信息。
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

扩展:可执行程序形成的时候,不是无序的二进制构成,有自己的格式的–可执行程序有自己的二进制格式–ELF格式

gcc/g++ 选项汇总

gcc/g++ 常用的选项和操作也就是 -o 选项还有 gcc file 直接生成可执行程序。

下面对其他选项做出一些补充:

-E :只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S :编译到汇编语言不进行汇编和链接
-c :编译到目标代码
-o :文件输出到文件
-static :此选项对生成的文件采用静态链接
-g :生成调试信息。GNU 调试器可利用该信息
-shared :此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库
-O0 :不做任何优化,这是默认的编译选项。
-O1 : 对程序做部分编译优化
-O2 :是比O1更高级的选项,进行更多的优化
-O3 :比O2更进一步的进行优化
-w :不生成任何警告信息
-Wall: 生成所有警告信息

安装和使用g++

g++是GNU的C++的编译器,使用前需要下载。

yum install gcc-c++

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
下载完成
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
查看版本
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
新建一个C++文件

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
编写一段C++代码
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库
用g++编译test.cpp文件
【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

总结:

今天我们学习了如何使用 gcc/g++ ,了解程序经过翻译环境形成可执行程序的过程。还初步认识了动静态库,实际上动静态库还有很多知识,等到基础 I/O 再进一步学习。接下来,我们将继续学习其他Linux环境基础工具的基本使用及配置。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库文章来源地址https://www.toymoban.com/news/detail-502216.html

到了这里,关于【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】03 GCC编译器的使用

     在使用gcc编译程序时,编译过程可以简要划分为4个阶段:         预处理、编译、汇编、链接 这个阶段主要处理源文件中的#indef、#include和#define预处理命令; 这里主要是把一些include的头文件和一些宏定义,放到源文件中。 编译命令: gcc  -E  -o  hello.i  hello.c 将经过预处

    2024年01月20日
    浏览(48)
  • 【Linux】编译器-gcc/g++使用

    个人主页 : zxctscl 文章封面来自:艺术家–贤海林 如有转载请先通知 在之前已经分享了 【Linux】vim的使用,这次来看看在云服务器上的编译器gcc。 我们先写一段简单的代码: 当我们进行编译的时候: 发现根本就编译不了。 这个是因为编译器版本的问题: 查看编译器的版

    2024年03月11日
    浏览(125)
  • Linux编译器——gcc/g++使用

    前言:  在上一篇,我们学习了关于文本编辑器 vim 的全部知识,今天给大家带来的是关于Linux编译器—gcc/使用的详细介绍。 本文目录  (一)温习程序的产生的过程 1、前言 2、程序的产生过程 3、🌜初步认识 gcc🌛 a) gcc的基本概念 b)gcc的基本特点 4、使用方法💻 (二)

    2023年04月17日
    浏览(50)
  • Linux--编译器-gcc/g++使用

    目录 前言 1.看一段样例  2.程序的翻译过程 1.第一个阶段:预处理 2.第二个阶段:编译 3.第三个阶段:汇编 4.第四个阶段:链接 3.程序的编译为什么是这个样子? 4. 关于编译器 5.链接(动静态链接) 1.首先,我们来看一段样例(见一下) 2.见完之后,我们来看一下程序的翻译

    2024年02月20日
    浏览(59)
  • Linux的学习之路:6、Linux编译器-gcc/g++使用

    本文主要是说一些gcc的使用,g++和gcc使用一样就没有特殊讲述。 目录 摘要 一、背景知识 二、gcc如何完成 1、预处理(进行宏替换) 2、编译(生成汇编) 3、汇编(生成机器可识别代码 4、链接(生成可执行文件或库文件) 5、函数库 6、静态库和动态库 7、gcc选项 三、思维导图

    2024年04月23日
    浏览(46)
  • 【Linux】编译器-gcc/g++与调试器-gdb的使用

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.gcc/g++语法 2.gcc的使用及编译器是如何\\\"翻译\\\"代码的? (1)预处理 (2)编译 (3)汇编

    2024年02月04日
    浏览(55)
  • 【Linux】编译器gcc和g++与调试器gdb的使用

    我们知道,一个程序被运行起来之后需要经历四个阶段然后才变成一个可执行的程序,他们分别为:预处理,编译,汇编和链接。下面我们将介绍这四个阶段的操作,测试代码如下: 1.1 预处理 预处理也叫预编译,程序在预处理阶段会完成如下操作: 展开头文件,将头文件中

    2024年02月07日
    浏览(41)
  • 【探索Linux】—— 强大的命令行工具 P.4(编译器 gcc/g++ 使用)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim ,也相信大家都掌握的不错,今天博主带大家了解一下Linux编译器 gcc/g++ 使用, 下面话不多说坐稳扶好咱们要开车了!!

    2024年02月12日
    浏览(51)
  • Linux:编译器 - gcc

    GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。 gcc是GCC中的C语言编译器,而g++是GCC中的C++编译器。本博客只讲解gcc,g++的语法和选项和gcc都是一致的。 gcc 编译

    2024年04月14日
    浏览(77)
  • Linux:详解(yum的使用、vim编辑器命令集合以及gcc/g++编译器的使用)

            在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序.         但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这

    2024年02月05日
    浏览(81)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包