【Linux】gcc和g++

👦个人主页:Weraphael

✍🏻作者简介:目前正在学习c++和Linux还有算法

✈️专栏:Linux

🐋 希望大家多多支持,咱一起进步!😁

如果文章有啥瑕疵,希望大佬指点一二

如果文章对你有帮助的话

欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 前言
  • [一、 Linux下编译C/C++代码](#一、 Linux下编译C/C++代码)
  • 二、gcc/g++是如何完成代码编译
      • [2.1 预处理](#2.1 预处理)
      • [2.2 编译](#2.2 编译)
      • [2.3 汇编](#2.3 汇编)
      • [2.4 链接](#2.4 链接)
  • 三、库
      • [3.1 函数库的概念](#3.1 函数库的概念)
      • [3.2 动态库](#3.2 动态库)
      • [3.3 静态库](#3.3 静态库)
      • [3.4 小结](#3.4 小结)

前言

大家的云服务器可能没有gcc或者g++指令,如果没有可以分别执行以下指令

  • sudo yum install -y gcc - gcc指令安装

  • sudo yum install -y gcc-c++ g++指令安装

注意:如果sudo指令有问题的,建议先看看这篇博客 -> 点击跳转

一、 Linux下编译C/C++代码

cpp 复制代码
gcc [.c文件]

执行完gcc [.c文件] 后,默认会生成可执行文件 a.out (前提是代码没有语法错误)

当然也有人想要为这个可执行文件起个名字,那么就要通过 -o选项 来实现

cpp 复制代码
gcc [.c文件] -o [新名字]

注意:g++ 也可以通过 -o 选项生成指定文件。其指令基本都是一样的

二、gcc/g++是如何完成代码编译

由于gcc和g++只有编译文件类型不同,其他大差不差,因此以下就以gcc为例

2.1 预处理

预处理会进行以下操作:

  • 去注释
  • 头文件展开
  • 条件编译
  • 宏替换

我们可以直接通过gcc中的-E选项 ,来查看预处理的现象。注意:预处理后的文件后缀为.i,此时仍然是C语言代码。目的是生成一个干净的C代码程序

cpp 复制代码
gcc -E [.c文件] -o [.i文件]	

接下来我们可以打开预处理阶段的文件test.i来看看里面的代码

大家有没有想过这样一个问题:头文件展开就是将头文件的内容给拷贝过来,那我们怎么知道头文件在哪?

  • 其实标准C库头文件(如stdio.h、stdlib.h等)通常位于 /usr/include 目录下。
  • 当然了,标准C++库头文件(如iostream、vector等)通常位于/usr/include/c++目录下,该目录下还会有不同版本的子目录,对应不同的C++标准和编译器版本。

2.2 编译

  • 编译阶段会进行:语法分析、词法分析、语义分析、符号汇总等,然后将合法的代码转为汇编代码。

编译阶段比较重要的一步就是符号汇总 ,它会各种符号汇总起来,形成符号表 ,符号表用于各种函数间的相互调用

我们可以直接通过gcc中的-S选项 ,来查看编译阶段的现象。注意:编译阶段的文件后缀为.s ,此时 .s文件里是源文件的汇编代码。

cpp 复制代码
gcc -S [.c文件] -o [重命名为.s文件]
// 注意[.c文件]也可以替换成[.i]文件

接下来,我们可以打开test.s查看汇编

2.3 汇编

  • 主要任务是将汇编代码转为二进制(转为计算机懂的语言),并生成符号表

【补充】 什么是符号表

这个东西相当于函数独一无二的地址
C语言的符号是 _函数名
C++更详细一些,通常为 _Z函数名长度+函数名+ 形参类型的首字母

我们可以直接通过gcc中的-o选项 ,来查看汇编阶段的现象。注意:汇编文件后缀为.o ,此时 .o文件将源文件转化为二进制文件。

cpp 复制代码
gcc -c [.c文件] -o [重命名为.o文件]

// 或者可以从[.s文件]开始编译
gcc -c [.s文件] -o [重命名为.o文件]

我们可以打开test.o来【欣赏】二进制文件

我们发现是一堆乱码,这是一个正常的现象,因为test.o本身是二进制文件,其,而vim是文本编辑器,自然而然就看不懂

但是我们可以使用工具 readelf:是一个用于查看和分析二进制可执行文件格式elf的工具。

cpp 复制代码
readelf -a [二进制文件]

【以下只截取了一部分】

注意:二进制文件不可执行,需要通过链接才能执行。

2.4 链接

  • 将可重定位目标的二进制文件(或称目标文件.o),和库进行链接形成可执行文件。
cpp 复制代码
// 两种写法
gcc [.c文件] -o [重命名可执行文件]	
gcc [.o文件] -o [重命名可执行文件]	


上面说了,目标文件需要和库进行链接,因此接下来我们来谈谈库。

三、库

3.1 函数库的概念

C程序中,并没有定义printf函数(我们只是调用函数),且在预编译中包含的stdio.h中也只有该函数的声明,而没有定义函数的实现。那么,是在哪里实现printf函数的呢?

在Linux系统中,它把C语言函数实现都被放到名为libc.so的库文件中去了 (路径:/usr/lib64/libc.so)。

没有特别指定时,gcc会到系统默认的搜索路径/usr/lib下进行查找,也就是链接到libc.so库函数中去。

如上图所示,在Linux中,C语言函数库是一个文件,以.so为后缀的称为动态库;以.a为后缀的称为静态库。

另外,库是有自己的命名规则的。以lib为前缀,name为中缀,.so.版本为后缀。而库真正的名字只有中缀那一块,这也就为什么libc.so称为C语言函数库的原因了。

注意:我们现在的机器上,默认只会安装动态库,静态库是默认没有安装的

【总结】

  • 函数的实现就是在库当中的

  • 库其实就是把源文件(.c文件),经过一定的翻译,然后打包,只给你提供一个文件(库文件)即可,不用给你提供给太多的源文件,也可以达到隐藏源文件的目的

  • 头文件提供方法的声明, 库文件提供方法的实现 + 我们自己的代码 == 可执行程序

  • 因此。库的作用:不用做很多重复的工作。

3.2 动态库

动态库即通过动态链接的库,动态库又称共享库,因为动态库中的内容是被所有程序共享的,简言之动态库中的代码只需要存在一份,程序需要使用时,直接通过对应位置调用就行了

在Linux中默认使用 动态链接 的方式,我们可以通过 指令ldd来查看文件的链接情况

我们还可以通过 file命令查看文件详细信息

3.3 静态库

静态库采用静态链接的方式;静态链接不同与动态链接共享的方式,如果程序调用静态库 ,会将自己所需要的代码拷贝至程序中 ,完成拷贝后,后续不需要再调用静态库。

如果想采用静态链接链接的方式编译程序,需要在编译时加上-static选项

cpp 复制代码
gcc [源文件] -o [自己取] -static	

而我们开头说了,我们的云服务器默认是没有静态库的,没有的可以通过sudo yum install -y glibc-static下载。还有我们也可以装一下c++的静态库sudo yum install -y libstdc++-static

当然,我们也可以通过ldd和file指令查看链接情况

由于静态链接是直接将需要的代码拷贝到程序中,因此最终生成的文件会变大,比较占空间

3.4 小结

【动态库】

  • 优点

    • 动态库因为是共享库,有效的节省资源(节省磁盘空间,内存空间,网络空间等)
  • 缺点

    • 动态库一旦缺失,导致各个程序都无法运行

静态库

  • 优点
    • 程序运行无需依赖库,可以独立运行
  • 缺点
    • 体积大,比较消耗资源,浪费空间
相关推荐
爱签AI电子合同32 分钟前
电子合同上手成本怎么测?易用性维度专项测评
服务器·人工智能·智能合约·企业微信
aixingkong9213 小时前
Nvidia为例 XPU的Multi-Host、Socket Direct 、GPUDirect、RDMA 技术点分析
服务器·网络·硬件架构·硬件工程
雯宝5 小时前
mnt_init 函数
linux
律宏阔11 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔11 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴11 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千12 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei3712 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei3712 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei3712 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化