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

news2024/12/25 12:34:29

在这里插入图片描述

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

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

文章目录

  • 前言
  • gcc 演示翻译环境
    • 1、预处理
    • 2、编译
    • 3、汇编
    • 4、链接
    • 总结
  • 动静态链接库
    • 1、库的认识
    • 2、链接方式
    • 3、动态库与静态库
    • 4、两种链接方式的使用
    • 5、debug和release
  • gcc/g++ 选项汇总
  • 安装和使用g++
  • 总结:

前言

在上一篇 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;
}

进行预处理 :

在这里插入图片描述

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

在这里插入图片描述

我们发现代码变为八百多行,这是因为头文件 #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,但是我们为了演示过程的连续性,我们统一从上次生成的文件开始执行指令。

进行编译 :

在这里插入图片描述

观察 file.s 文件内容:

在这里插入图片描述

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

3、汇编

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

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

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

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

汇编指令 :

gcc -c file.s -o test.o

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

进行汇编 :

在这里插入图片描述

file.o 内容:
在这里插入图片描述

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

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

那么该文件可以执行吗?

在这里插入图片描述

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

我们将其提权试试:

在这里插入图片描述

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

在这里插入图片描述

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

4、链接

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

链接指令 :

gcc file.o -o myfile

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

进行链接 :

在这里插入图片描述

再执行生成的可执行程序 test :
在这里插入图片描述
总结:链接后的可执行文件才可以执行。

总结

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

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

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

动静态链接库

1、库的认识

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

在链接的过程中,需要对形成的二进制文件和库文件进行合并从而形成可执行程序,这边就调用了库。库是能成功编译的必要条件。
在这里插入图片描述
我们一直在使用库,至少是语言上的库。

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

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

在这里插入图片描述

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

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

在这里插入图片描述

在linux 下,库分两种 :

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

基于上面的格式,不同的库还可能会有版本,例如 test 程序就依赖了libc.so.6 ,后面的 .6 就是版本:
在这里插入图片描述

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

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

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

不止可执行程序,就连指令也依赖于库,我们观察几个指令:(我们可以使用ldd指令查看动态链接的可执行文件所依赖的库)
在这里插入图片描述

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

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

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

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

2、链接方式

Linux 的链接方式就两种:

动态链接
静态链接

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

用 file 指令查看 test 文件的类型:
在这里插入图片描述

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

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

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

3、动态库与静态库

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

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

动态库优缺点:

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

静态库优缺点:

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

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

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

4、两种链接方式的使用

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

而静态链接则需要通过特定方式来使用,并且 Linux 默认只装了动态库,静态库是没装的,所以先安装一下:
在这里插入图片描述
C语言静态库:

sudo yum install -y glibc-static

C++静态库:

sudo yum install -y libstdc++-static

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

静态链接的使用方式为:

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

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

在这里插入图片描述

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

再用 file file-static 查看一下文件类型:
在这里插入图片描述

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

5、debug和release

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

在Linux当中gcc/g++默认生成的可执行程序是release版本的,是不可被调试的。如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g选项。
在这里插入图片描述

对同一份源代码分别生成其release版本和debug版本的可执行程序,并通过ll指令可以看到,debug版本发布的可执行程序的大小比release版本发布的可执行程序的大小要大一点,其原因就是以debug版本发布的可执行程序当中包含了更多的调试信息。
在这里插入图片描述

扩展:可执行程序形成的时候,不是无序的二进制构成,有自己的格式的–可执行程序有自己的二进制格式–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++

在这里插入图片描述
下载完成
在这里插入图片描述
查看版本
在这里插入图片描述
新建一个C++文件

在这里插入图片描述
编写一段C++代码
在这里插入图片描述
用g++编译test.cpp文件
在这里插入图片描述

总结:

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

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/610314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python处理DICOM文件

Python处理DICOM文件 DICOM (Digital Imaging and Communications in Medicine)是医疗图像和数据的标准&#xff0c;用于存储和交换医学图像和相关信息。在医疗领域中&#xff0c;DICOM文件是医生和医学技师进行诊断和治疗的必要条件。在本文中&#xff0c;我们将介绍如何使用…

Linux下配置Qt6安卓开发环境

安装JDK 选择自己定义JDK安装路径 点击如下图按钮 安装SDK 提示TLS初始化失败 由于HTTPS问题造成无法下载,暂用Android Studio来安装Android SDK 成功安装SDK 安装NDK与命令行工具 正在下载NDK及命令行工具 NDK与工具下载完成 配置QT的Android SDK路径 配置NDK路径 选择ND…

Nginx服务性能和安全优化(念念不忘,必没回响)

一、配置Nginx隐藏版本相关信息 1.隐藏版本号 修改 nginx.conf 文件&#xff0c;在http块中添加字段后&#xff0c;重载服务 获取报文信息并查看&#xff08;浏览器查看或使用命令&#xff09; 2.修改版本号及相关信息 如果做了上一步在nginx.conf 中添加了 server_tokens…

数据结构-二分查找

1.1 什么是算法&#xff1f; 定义 在数学和计算机科学领域&#xff0c;算法是一系列有限的严谨指令&#xff0c;通常用于解决一类特定问题或执行计算 In mathematics and computer science, an algorithm (/ˈlɡərɪəm/) is a finite sequence of rigorous instructions, …

【Spring Cloud Gateway】⑥SpringBoot3.x集成SpringDoc指南

文章目录 背景本地开发环境介绍pom.xml主要依赖application.yml效果预览动态生成swagger文档分组效果预览在线文档 背景 Spring Cloud Gateway使用Netty作为嵌入式服务器&#xff0c;并基于响应式Spring WebFlux。做为微服务网关&#xff0c;多个微服务把API挂在Gateway上&…

轻量实时操作系统学习(二)

306xH系列架构 主系统包含以下部件&#xff1a; maters&#xff1a;RISC-V CPU、DMA、CORESIGHTslaves&#xff1a;嵌入式SYSRAM、嵌入式Flash memory、系统外设 这些模块通过AMBA总线架构互连&#xff0c;如图所示。 TCM_BUS&#xff1a;此总线将RISC-V CPU的TCM接口与存…

STM32学习(十四)

低功耗 降低集成电路的能量消耗。 低功耗特性对用电池供电的产品&#xff1a; 更小电池体积&#xff08;降低了大小和成本&#xff09; 延长电池寿命 电磁干扰更小&#xff0c;提高无线通信质量 电源设计更简单&#xff0c;无需过多考虑散热问题 STM32具有运行、睡眠、停止和…

【SQL Server】数据库开发指南(八)高级数据处理技术 MS-SQL 事务、异常和游标的深入研究

本系列博文还在更新中&#xff0c;收录在专栏&#xff1a;#MS-SQL Server 专栏中。 本系列文章列表如下&#xff1a; 【SQL Server】 Linux 运维下对 SQL Server 进行安装、升级、回滚、卸载操作 【SQL Server】数据库开发指南&#xff08;一&#xff09;数据库设计 【SQL Se…

Flutter 笔记 | Flutter 核心原理(七)The key is the key!

题外话 本文这个标题其实让我想起了电影《蝙蝠侠大战超人&#xff1a;正义黎明》中的一句话&#xff0c;在该片中&#xff0c;从未来穿越回来的闪电侠对蝙蝠侠发出警告&#xff1a; It’s Lois&#xff01; She’s the key&#xff01; 【布鲁斯&#xff0c;是露易丝&#xff…

chatgpt赋能python:Python增量备份:保障数据安全,提高效率

Python增量备份&#xff1a;保障数据安全&#xff0c;提高效率 现今&#xff0c;越来越多的企业和个人都需要使用计算机存储数据&#xff0c;这些数据可能是各种各样的&#xff0c;例如文件、数据库、邮件等等&#xff0c;这些数据的安全保障是至关重要的。 正是基于这样的背…

chatgpt赋能python:Python多行转一行:最简便的方法

Python多行转一行&#xff1a;最简便的方法 Python是一个既神奇又神奇&#xff08;fully magical&#xff09;的编程语言。但有时候&#xff0c;我们用Python编写的程序会产生多行代码&#xff0c;而需要把这些多行代码转换为一行以便于复制和粘贴。这种情况下&#xff0c;我们…

chatgpt赋能python:Python备份数据库——保障数据安全,防止数据丢失

Python备份数据库——保障数据安全&#xff0c;防止数据丢失 在现代社会&#xff0c;数据被称为新的石油&#xff0c;数据的意义愈发重要。数据的丢失可能会导致不可挽回的损失,给企业造成巨大的财务损失&#xff0c;更为重要的是企业形象的损失。备份数据是保护数据最好的途径…

chatgpt赋能python:Python奇偶求和函数

Python奇偶求和函数 Python是一种简单易学、高效的编程语言&#xff0c;具有丰富的库和工具&#xff0c;让程序员能够快速编写出各种各样的应用程序。Python中的函数可以让程序更加模块化&#xff0c;更加易于维护和扩展。其中&#xff0c;奇偶求和函数是一个很好的例子&#…

chatgpt赋能python:Python培训:成为一名高薪Python工程师

Python培训&#xff1a;成为一名高薪Python工程师 Python已成为当今最流行的编程语言之一&#xff0c;它广泛应用于人工智能、机器学习、数据科学和Web开发等各个领域。许多公司都在寻找经验丰富的Python工程师来开发他们的产品。如果你想成为一名高薪Python工程师&#xff0c…

创客匠人CEO蒋洪波:用门店思维做直播

互联网时代&#xff0c;转型线上做知识付费成为教育培训行业的主流&#xff0c;直播教学成为新型的教学模式受到了广泛认可。很多老师在线下培训深耕多年&#xff0c;知识储备丰富&#xff0c;但想要转型线上又缺少方法&#xff0c;缺少去改变的欲望&#xff0c;怕转型做线上直…

区块链的基本介绍

目录 1、简介 2、区块链的分类 2.1 公有链 2.2 联盟链 2.3 私有链 3、区块链特征 4、区块链结构 5、区块链对记账权利的分配方式 5.1 POW 5.2 PoS 5.3 DPoS 6、Defi、NFT、 gameFi 7、DAPP 7.1 DAPP 的核心要素 8、比特币 8.1 比特币简介 8.2 比特币数字签名…

白话ES搜索相关性问题

之前使用es&#xff0c;更多的是使用term查询&#xff0c;和agg聚合分析。对相关性关注较少。实际上es擅长的是做模糊搜索&#xff0c;相关性搜索。 ES是一个开源的通用的检索工具&#xff0c;能满足百分之八十的需求。相关性这个问题&#xff0c;是一个非常有意思的问题&#…

卡尔曼滤波与组合导航原理笔记(一) 第一部分 滤波的基本概念、递推最小二乘

文章目录 一、滤波的基本概念1、传统数字滤波器2、现代控制中的状态观测器3、最优估计的含义4、温度估计的例子1.问题描述2.分析 二、递推最小二乘 课程链接&#xff1a;https://www.bilibili.com/video/BV11K411J7gp/?p1 参考书目&#xff1a;《捷联惯导算法与组合导航原理》…

搭建本地MQTT服务器实现局域网通信

在这里mqtt就不多做介绍了直接上手怎么搭建本地服务器 一-. 我们先下载一个emqx&#xff0c;我们可以去官网下载免费的 https://www.emqx.io/https://www.emqx.io/ 下载完成之后我们打开这个文件夹 然后进入bin目录在左上角输入cmd然后回车 如果操作成功会来到这个界面 在这…

不压缩打包layui

手动打包 下载layui源码&#xff08;当前版本2.6.4&#xff09;&#xff0c;并解压缩 下载地址&#xff1a;layui gitee 安装nodejs&#xff08;v10.24.1&#xff09; 下载链接 windows-x64 安装cnpm npm install -g cnpm -registryhttps://registry.npm.taobao.org全局安…