【Linux】gcc/g++的使用

图片名称
🎉博主首页: 有趣的中国人

🎉专栏首页: Linux

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构

在这里插入图片描述

小伙伴们大家好,本片文章将会讲解Linux中gcc/g++使用的相关内容。


如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!

文章目录

  • 1. 什么是gcc/g++
  • 2. 编译运行gcc/g++的语法
  • 3. gcc/g++编译的四个步骤
    • 3.1 ==🔎<font color = blue size = 4><b>预处理🔍==
    • 3.2 ==🔎<font color = blue size = 4><b>编译🔍==
    • 3.3 ==🔎<font color = blue size = 4><b>汇编🔍==
    • 3.4 ==🔎<font color = blue size = 4><b>链接🔍==
    • 3.5 ==<font color = blue size = 4><b>🔎编译器的自举过程🔍==
  • 4. 详解链接
    • 4.1 ==🔎<font color = blue size = 4><b>动态库&动态链接🔍==
    • 4.2 ==🔎<font color = blue size = 4><b>静态库&静态链接🔍==
    • 4.2 ==🔎<font color = blue size = 4><b>动态库动态链接&静态库静态链接的优缺点🔍==



1. 什么是gcc/g++


GCC(GNU Compiler Collection)是一套由GNU计划开发的编译器集合,它是一种开源的编译器套件,用于编译和运行C、C++、Fortran、Ada、以及其他一些编程语言的程序。其中,g++是GCC中专门用于编译C++程序的工具

由于其开放源代码的特性,GCC已经成为许多操作系统和平台上的标准编译器,例如Linux、GNU Hurd、Mac OS X等

g++是GCC中用于编译C++源代码的前端工具。它支持标准的C++语法和语言特性,并提供了丰富的编译选项和优化功能,以便用户根据需要进行配置和调整。使用g++,开发者可以将C++源代码编译成可执行程序或者库文件,从而在各种平台上运行他们的程序。


🔎关于C、C++的后缀🔍

在Linux系统中C语言正常以.c为后缀。

C++一般有三个后缀:

1. filename.cpp

2. filename.cc

3. filename.cxx

🔎安装gcc/g++🔍

输入命令安装gcc:

# 我这里已经下载过了
[dsj@alicloud-dsj ~]$ sudo yum install -y gcc # 输入此行命令即可下载
[sudo] password for dsj:                      # 这里要sudo提权,如果是root就不需要
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
base                                                                                                                                | 3.6 kB  00:00:00     
epel                                                                                                                                | 4.7 kB  00:00:00     
extras                                                                                                                              | 2.9 kB  00:00:00     
updates                                                                                                                             | 2.9 kB  00:00:00     
(1/3): epel/x86_64/updateinfo                                                                                                       | 1.0 MB  00:00:00     
(2/3): epel/x86_64/primary_db                                                                                                       | 7.0 MB  00:00:00     
(3/3): updates/7/x86_64/primary_db                                                                                                  |  27 MB  00:00:00     
Package gcc-4.8.5-44.el7.x86_64 already installed and latest version

输入命令安装g++:

# 我这里已经下载过了
[dsj@alicloud-dsj ~]$ sudo yum install gcc-c++  # 输入此行命令即可下载g++
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Package gcc-c++-4.8.5-44.el7.x86_64 already installed and latest version
Nothing to do

查看gcc/g++版本:

[dsj@alicloud-dsj ~]$ gcc --version #输入此行命令查看gcc版本
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.[dsj@alicloud-dsj ~]$ g++ --version #输入此行命令查看g++版本
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2. 编译运行gcc/g++的语法


🔎编译gcc的语法🔍

先确保我们目录中存在C文件,然后输入以下命令进行编译,生成可执行文件:

gcc [要编译的文件] -o[要生成的文件名]
or
gcc -o[要生成的文件名] [要编译的文件]

例如:

[dsj@alicloud-dsj lesson10]$ gcc test.c -o my.exe -std=c99 #输入-std=c99说明以c99标准进行编译
[dsj@alicloud-dsj lesson10]$ ll
total 16
-rwxrwxr-x 1 dsj dsj 8408 May  8 15:42 my.exe
-rw-rw-r-- 1 dsj dsj 3087 May  8 10:39 test.c

在这里插入图片描述

🔎编译g++的语法🔍

先确保我们目录中存在C++文件,然后输入以下命令进行编译,生成可执行文件:

g++ [要编译的文件] -o[要生成的文件名]
or
g++ -o[要生成的文件名] [要编译的文件]

例如:

[dsj@alicloud-dsj lesson10]$ g++ test.cc -o myc++.exe -std=c++11 #输入-std=c++11说明以c++11标准进行编译
[dsj@alicloud-dsj lesson10]$ ll
total 32
-rwxrwxr-x 1 dsj dsj 8976 May  8 15:52 myc++.exe
-rwxrwxr-x 1 dsj dsj 8408 May  8 15:42 my.exe
-rw-rw-r-- 1 dsj dsj 3087 May  8 10:39 test.c
-rw-rw-r-- 1 dsj dsj  141 May  8 15:52 test.cc

在这里插入图片描述


🔎运行可执行文件🔍

输入命令./[可执行文件名]即可运行。

在这里插入图片描述


3. gcc/g++编译的四个步骤


使用 GCC 或者 g++ 编译 C 或者 C++ 程序通常包括以下四个步骤:

1. 预处理

2. 编译

3. 汇编

4. 链接


3.1 🔎预处理🔍


预处理阶段编译器通常会有以下步骤:

1. 头文件的展开

2. 宏替换

3. 去注释

4. 条件编译

我们可以输入以下命令让.c文件停留在预处理阶段进行查看:

[dsj@alicloud-dsj lesson10]$ gcc -E test.c -o test.i #输入这个命令
[dsj@alicloud-dsj lesson10]$ ll
total 52
-rwxrwxr-x 1 dsj dsj  8976 May  8 15:52 myc++.exe
-rwxrwxr-x 1 dsj dsj  8408 May  8 15:42 my.exe
-rw-rw-r-- 1 dsj dsj  3087 May  8 10:39 test.c
-rw-rw-r-- 1 dsj dsj   141 May  8 15:52 test.cc
-rw-rw-r-- 1 dsj dsj 17250 May  8 16:15 test.i #生成这个文件,停留在预处理阶段
[dsj@alicloud-dsj lesson10]$ vim test.i #输入此行命令查看test.i文件

查看此文件:

在这里插入图片描述


我们发现虽然源文件只有100多行,但是.i这个文件就有800多行,这是因为头文件被展开了,并且注释也被去除了,宏也被替换了。


💻条件编译

我们先用条件编译写一下如下的代码:

#include <stdio.h>int main()
{
#ifdef V1printf("功能1\n");#elif V2printf("功能1\n");printf("功能2\n");printf("功能3\n");
#elseprintf("功能1\n");printf("功能2\n");printf("功能3\n");printf("功能4\n");printf("功能5\n");printf("功能6\n");
#endifreturn 0;
}

因为这里并没有定义V1, V2,所以会执行else的内容:

在这里插入图片描述

我们可以在编译的时候输入以下指令就可以给源文件增加宏定义:

[dsj@alicloud-dsj test]$ gcc -D V1=1 test.c -o test.exe

在这里插入图片描述

3.2 🔎编译🔍


编译阶段编译器通常会有以下步骤:

1. 生成汇编代码

2. 检查语法(词法分析、语法分析、语义分析等)

我们可以输入以下命令让.i文件停留在编译阶段进行查看:

[dsj@alicloud-dsj lesson10]$ gcc -S test.i -o test.s -std=c99

在这里插入图片描述

vim查看此文件:

在这里插入图片描述

3.3 🔎汇编🔍


汇编阶段编译器主要会有以下步骤:

将汇编代码转换成机器可识别的二进制代码。


我们可以输入以下命令让`.s`文件停留在汇编阶段进行查看:
[dsj@alicloud-dsj lesson10]$ gcc -c test.s -o test.o

在这里插入图片描述

vim查看此文件:

在这里插入图片描述

emmmmm,发现是看不懂的二进制文件,没错,这是机器识别的文件,没打算给我们看懂。


3.4 🔎链接🔍


链接阶段编译器通常会有以下步骤:

链接阶段就是将汇编阶段已经生成的二进制文件和所需要的进行链接,最终生成可执行程序的过程。


我们可以输入以下命令让.o文件生成可执行程序:


在这里插入图片描述
在这里插入图片描述

3.5 🔎编译器的自举过程🔍


首先我们来思考一个问题:为什么在编译时必须要走这4个过程,不能直接到链接阶段生成可执行程序吗?要讲解这个问题我们先回溯一下历史:

回溯历史:

我们知道计算机最早的编程是通过那种打孔的小纸条来实现的,因为这样编程太过于复杂,随后又出现了汇编语言。

然而所有的计算机程序最终都需要被翻译成计算机能够理解的二进制形式才能执行,所以在汇编语言发行的时候肯定也解决了将汇编语言翻译成二进制形式的问题。

所以对于我们的C/C++语言,如果直接转换成二进制语言,实际上是可行的,但是实现起来难度太大,如果说运用前辈们的成果,先将C/C++翻译成汇编语言,在翻译成二进制语言,这样的难度肯定就会小很多,这就是为啥要经历编译、汇编等阶段的原因。

然而此时的问题又来了,第一个汇编语言程序是怎么被编译出来的呢?是依靠编译器吗?编译器又是哪款语言写的呢?

其实当汇编发行的时候,先用二进制语言写了一份汇编语言的编译器,然后就可以把汇编语言学的代码放到这个编译器中进行编译,因为编译器也是属于软件,所以我们也可以用汇编语言写一份汇编语言的编译器,再放到二进制语言写的汇编语言编译器中进行编译,就形成了汇编语言的编译器,这个过程就叫做编译器的自举。

下面是详细的解释:

编译器的自举是指用编程语言(例如汇编语言)编写一个编译器,然后使用该编译器来编译其自身的源代码。这个过程可以分为几个步骤:

  1. 编写第一个版本的编译器: 初始阶段,程序员会使用另一种已经存在的编程语言(通常是汇编语言或高级语言)来编写一个最基本的编译器。这个编译器可以将源代码(例如C语言)转换为目标机器的汇编语言或者机器码。
  2. 使用第一个编译器编译自身源代码: 一旦第一个版本的编译器完成,程序员会使用它来编译其自身的源代码。这意味着用该编译器编译的结果将是一个新版本的编译器。
  3. 重复此过程: 新版本的编译器可以更加完善和高效,程序员可以使用它来编译自身的源代码,生成更新的版本。这个过程可以一遍又一遍地重复,每一次迭代都会改进编译器的功能、性能和稳定性。

通过这种方式,编译器的自举实现了编译器的持续改进和演化。它也证明了编译器本身是一个软件程序,可以用其它编程语言来编写,而不仅仅局限于机器语言或者汇编语言。这个过程展示了计算机科学中有趣的自指特性。


4. 详解链接


刚才说过,链接实际上就是把汇编阶段生成的二进制目标文件和所需要的库文件相结合,形成可执行文件的过程。


那么问题来了,这个库是什么,它存在在那里,为什么就能找到呢?



我们接下来一一解答。

在我们的头文件中只是包含了一些内置类型函数的声明,例如下图的printf,那么具体的函数实现在哪里呢?

在这里插入图片描述

对于每一门语言,在被发行的时候都有自己的库函数,这里面存放这一些常用函数的具体实现(方法集),例如输入输出函数等,然后他会给出你一些头文件,这些头文件就相当于是这些库的说明书,供你使用。


并且在编译阶段编译器就会告诉你应该去哪个位置去找到对应的方法。


我们可以用一下命令看一下Linux下C所依赖的库是什么:


在这里插入图片描述

[dsj@alicloud-dsj lesson10]$ ldd test.exelinux-vdso.so.1 =>  (0x00007ffcfc7db000)libc.so.6 => /lib64/libc.so.6 (0x00007f6d9eb9d000)/lib64/ld-linux-x86-64.so.2 (0x00007f6d9ef6b000)
[dsj@alicloud-dsj lesson10]$ ls /lib64/libc.so.6 -l
lrwxrwxrwx 1 root root 12 Sep 19  2023 /lib64/libc.so.6 -> libc-2.17.so
[dsj@alicloud-dsj lesson10]$ file test.exe
test.exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=946a88d4c5e0c0a19483beb1d83eeb28686d5d4e, not stripped
[dsj@alicloud-dsj lesson10]$ 

4.1 🔎动态库&动态链接🔍


我们可以看到C所依赖的库是 /lib64/libc.so.6,这个库中存放的就是内置给你的函数的具体实现方法,但是是二进制的文件,可以看一下:

在这里插入图片描述


💻动态库

这个库是以.so的后缀,一般以这个为后缀的文件就叫做动态库。


💻动态链接

动态链接就是在程序运行时由操作系统的动态链接器动态地加载动态链接库文件,不会在编译时将库文件的代码和数据合并到可执行文件中。

可以用file看一下文件的具体类型:

在这里插入图片描述

说明这个可执行文件是动态链接的(共享库也就是动态库)。

4.2 🔎静态库&静态链接🔍


💻静态库

在Linux中,静态库通常以.a为后缀,但是一般情况下不会自带,要自己手动下载。

💻静态库的下载

sudo yum install -y glibc-static # C语言静态库
sudo yum install -y libstdc+±static # C++静态库

这样我们编译一个文件就可以以静态的形式进行编译:

[dsj@alicloud-dsj lesson10]$ gcc test.c -o static_test.exe -static -std=c99

在这里插入图片描述

💻静态链接

在静态链接的情况下,编译器会在编译阶段将所需的库函数的代码和数据直接合并到最终的可执行程序中,而不是在运行时动态加载和链接库文件。

这意味着可执行文件会变得更大,因为它包含了所有依赖的库的代码和数据,但同时也意味着程序在运行时不需要依赖外部的库文件,因为所有的代码和数据都已经包含在可执行文件中了。

在这里插入图片描述

4.2 🔎动态库动态链接&静态库静态链接的优缺点🔍


动态库&动态链接:
1. 因为Linux中的很多指令都要依赖此动态库,因此他不能丢失
2. 它相较于静态链接更节省资源空间
静态库&静态链接
1. 因为静态链接会在编译阶段把所有需要的函数全都加载到内存中,因此它不需要依赖其他东西,和库无关,跨平台性较强
2. 但是太费资源、空间。

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

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

相关文章

【Linux】CAN根据时钟频率、波特率计算采样点详解

1、采样点知识回顾 参考博客:【CAN】知识点:帧类型、数据帧结构、传输速率、位时间、采样点 CAN 采样点是指在一个数据位的传输周期内,接收器实际采样数据的时间点。这个时间点是以百分比来表示的,它决定了在数据位的传输周期中,何时读取数据位的值。 正确设置采样点对…

js api part3

环境对象 环境对象&#xff1a; 指的是函数内部特殊的 变量 this &#xff0c; 它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 函数的调用方式不同&#xff0c;this 指代的对象也不同 【谁调用&#xff0c; this 就是…

Qt | QLineEdit 类(行编辑器)

01、上节回顾 Qt | QComboBox(组合框)02、QLineEdit 1、QLineEdit 类是 QWidget 类的直接子类,该类实现了一个单行的 输入部件,即行编辑器,见右图 2、验证器(QValidator 类)和输入掩码简介:主要作用是验证用户输入的字符是否符合验证器 的要求,即限制对用户的输入,比…

论文阅读_使用有向无环图实现流程工程_AgentKit

英文名称: AgentKit: Flow Engineering with Graphs, not Coding 中文名称: AgentKit&#xff1a;使用图而非编码进行流程工程 链接: https://arxiv.org/pdf/2404.11483.pdf 代码: https://github.com/holmeswww/AgentKit 作者: Yue Wu, Yewen Fan, So Yeon Min, Shrimai Prabh…

Julia 语言环境安装与使用

1、Julia 语言环境安装 安装教程&#xff1a;https://www.runoob.com/julia/julia-environment.html Julia 安装包下载地址为&#xff1a;https://julialang.org/downloads/。 安装步骤&#xff1a;注意&#xff08;勾选 Add Julia To PATH 自动将 Julia 添加到环境变量&…

C语言 函数的嵌套与递归 调用

本文 我们来说函数的嵌套调用和递归调用 在很多大型项目中 我们肯定不可能将所有逻辑都写在一个函数中 肯定要按功能拆解成多个特定的功能函数 函数并不允许嵌套调用&#xff0c;但是 允许在逻辑代码中嵌套调用 所谓函数嵌套调用 就是在一个函数中调用另一个函数&#xff0c;而…

【计算机毕业设计】基于SSM++jsp的菜匣子优选系统【源码+lw+部署文档+讲解】

目录 第一章 绪 论 第二章 关键技术的研究 2.1 JSP技术介绍 2.2 JAVA简介 2.3 ECLIPSE 开发环境 2.4 Tomcat服务器 2.5 MySQL数据库 第三章 系统分析 3.1 系统设计目标 3.2 系统可行性分析 3.3 系统功能分析和描述 3.4系统UML用例分析 3.4.1管理员用例 3.4.2用户用例 3.5系统流…

C语言 计数控制循环

今天 我们来说 计数控制的循环 对于循环次数 我们已知的循环 我们称之为 计数控制的循环 这种情况 我们一般选择 for来实现 更为方便 先看一个案例 求 1 到 N 的累加合 我们代码可以这样写 #define _CRT_SECURE_NO_WARNINGS//禁用安全函数警告 #pragma warning(disable:6031…

信创基础硬件之芯片

信创基础硬件之芯片 文章目录 信创基础硬件之芯片服务器服务器的定义服务器的功能服务器的构成服务器的性能 处理器&#xff08;CPU&#xff09;CPUGPUDPU CPU的分类按CPU指令集架构分类按CPU体系架构分类 CPU产业链六大国产CPU公司详解海光飞腾鲲鹏兆芯龙芯申威 国产CPU对比从…

Linux网络编程:TCP编程实现

目录 1、前言 2、函数介绍 2.1 socket函数 与 通信域 2.2 bind函数 与 通信结构体 2.2.1 domain通信地址族 与 通信结构体 2.2.2 IPv4地址族结构体 2.2.3 通用地址族结构体 2.2.4 示例&#xff1a;为套接字fd绑定通信结构体addr 2.3 listen函数 与 accept函数 …

了解外汇询价和锁价,全球交易中的关键概念

外汇市场是全球交易量最大的金融市场之一&#xff0c;每天都有大量的货币买卖活动。在外汇交易中&#xff0c;询价和锁价是两个关键概念&#xff0c;它们不仅影响交易者的决策&#xff0c;还关系到交易的成本和风险控制。为了帮助交易者更好地理解和应用这两个概念&#xff0c;…

Linux课程机房虚拟机

Linux课程机房虚拟机 机房虚拟机&#xff08;默认不能联网的&#xff09;&#xff1a; 百度网盘&#xff1a;https://pan.baidu.com/s/1WqSvqB3Y7b_D4690CDBlJA?pwdaugc 123网盘&#xff1a;https://www.123pan.com/s/tQ0UVv-LiolA.html提取码:F4xm ‍ 联网使用说明&…

小trick

https://codeforces.com/gym/105104/problem/C const int N 1e6 10;int T, n, x; ull v[N];int main() {mt19937_64 rng(random_device{}()); // 注意这种生成随机数的方法&#xff01;&#xff01;&#xff01;F(i, 0, N - 10)v[i] rng();for (R(T); T --; ) {R(n);map &…

笔记2:cifar10数据集获取及pytorch批量处理

&#xff08;1&#xff09;cifar10数据集预处理 CIFAR-10是一个广泛使用的图像数据集&#xff0c;它由10个类别的共60000张32x32彩色图像组成&#xff0c;每个类别有6000张图像。 CIFAR-10官网 以下为CIFAR-10数据集data_batch_*表示训练集数据&#xff0c;test_batch表示测试…

分成互质组

题目描述: 给定 n 个正整数&#xff0c;将它们分组&#xff0c;使得每组中任意两个数互质。 至少要分成多少个组&#xff1f; 输入格式 第一行是一个正整数 n。 第二行是 n 个不大于10000的正整数。 输出格式 一个正整数&#xff0c;即最少需要的组数。 #include<iostream…

DDR5和LPDDR4/5 命令解析

关键名称介绍 DDR5 SDRAM和LPDDR4/5都采用了高级的命令集来支持更高效的内存管理和操作,其中“Multi-purpose command (MPC)”、“Mode Register Read (MRR)”、“Mode Register Write (MRW)”,以及“Write Pattern Command”是几种关键的命令类型,它们在内存初始化、配置和…

Windows 虚机扩容C盘

Windows 虚机扩容C盘 操作思路1、新增磁盘容量2、划分磁盘空间3、扩容对应盘 操作步骤 操作思路 1、新增磁盘容量 2、划分磁盘空间 3、扩容对应盘 操作步骤 1、虚机新增磁盘空间 先确认宿主机是否有足够空间&#xff0c;有足够空间后&#xff0c;编辑虚机&#xff0c;增加…

【Java】山外有山,类外还有类

【Java】山外有山&#xff0c;类外还有类 内部类是Java语言中的一种特性&#xff0c;它允许在另一个类中定义一个类。 内部类可以是静态的&#xff08;不依赖于外部类的实例&#xff09;&#xff0c;也可以是非静态的&#xff08;依赖于外部类的实例&#xff09;。 在本篇博…

不止是搭建 | 极空间虚拟机安装一个可做生产力的Ubuntu桌面系统以及后续优化

不止是搭建 | 极空间虚拟机安装一个可做生产力的Ubuntu桌面系统以及后续优化 哈喽小伙伴们好&#xff0c;偶是Stark-C~ 我在上篇极空间文章中不是给小伙伴们分享了使用虚拟机安装软路由固件『iStoreOS』的教程嘛&#xff1a; 打造Docker完全体&#xff0c; 开箱即用的各类插…

通过 Java 操作 redis -- hash 哈希表基本命令

目录 使用命令 hset&#xff0c;hget 使用命令 hexists 使用命令 hdel 使用命令 hkeys&#xff0c;hvals 使用命令 hmget&#xff0c;hmset 关于 redis hash 哈希表类型的相关命令推荐看Redis - hash 哈希表 要想通过 Java 操作 redis&#xff0c;首先要连接上 redis 服务…