【Linux】深度解析与实战应用:GCC/G++编译器入门指南

🔥 个人主页:大耳朵土土垚
🔥 所属专栏:Linux系统编程

这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉

文章目录

  • 1. gcc/g++简介
  • 2. gcc/g++的基本使用
  • 3. 函数库
  • 4. 调试
  • 5. 总结

1. gcc/g++简介

  在Linux系统中,GCC(GNU Compiler Collection)是极其重要且广泛使用的编译器,它支持多种编程语言,包括C、C++、Objective-C、Java、Fortran等。GCC以其高效、灵活和跨平台的特点赢得了开发者的青睐。本文将详细介绍GCC中的C编译器gcc和C++编译器g++的基本使用方法和编译过程。

  GCC(GNU Compiler Collection)是一个由GNU项目开发的编译器套件,原名GNU C Compiler,但随着发展,它已支持多种编程语言的编译。GCC最初只能编译C语言,但现在的GCC通过不同的前端模块支持多种语言。GCC支持多种硬件平台,并且具备跨平台交叉编译的能力。

  在Linux系统中,gcc和g++是GCC套件中用于编译C和C++程序的工具。gcc专门用于C语言程序的编译,而g++则专注于C++程序的编译。虽然两者在编译C程序时可能表现相似,但在处理C++程序时,g++会链接C++的标准库,而gcc默认链接C的标准库。


2. gcc/g++的基本使用

gcc和g++的基本使用格式如下:

gcc [选项] 要编译的文件 [选项] [目标文件]  
g++ [选项] 要编译的文件 [选项] [目标文件]

我们可以通过下面的指令来判断是否已经安装gcc/g++:

gcc --version  
g++ --version

如果没有安装,大家可以先搜索安装gcc/g++对应的指令进行安装,因为不同的Linux发行版本安装指令或多或少有些差异,所以这里就不过多介绍。

gcc和g++的一些常用的选项包括:

-E:仅进行预处理,不进行编译和汇编。
-S:生成汇编代码,但不进行汇编和链接。
-c:生成目标代码(.o文件),但不进行链接。
-o:指定输出的文件名。
-static:使用静态链接生成可执行文件。
-g:生成调试信息,供GDB等调试器使用。

首先对于一个C或C++程序从源代码到可执行文件的编译过程通常包括四个步骤:预处理、编译、汇编和链接。

✨【预处理(进行宏替换)】:
  预处理功能主要包括宏定义,文件包含(#include)、条件编译(如#ifdef、#ifndef、#endif)以及删除注释等。

实例:

gcc -E hello.c -o hello.i
  • 这条命令会生成一个预处理后的文件hello.i,其中包含了所有宏展开和文件包含的结果;
  • hello.c 是要预处理的文件;
  • 选项“-E”,该选项的作用是让 gcc在预处理结束后停止编译过程;
  • 选项“-o”指向目标文件hello.i;
  • hello.i文件为已经预处理的C原始程序也就是目标文件。

✨【编译(生成汇编)】:
  在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。

实例:

gcc -S hello.i -o hello.s
  • 这条命令会生成一个汇编文件hello.s;
  • hello.i 是要编译的文件;
  • 选项“-S”,该选项的作用是让 gcc在预处理、编译后停止进行汇编,生成汇编代码
  • 选项“-o”指向目标文件hello.s;
  • hello.s文件为已经编译后的目标文件。

✨【汇编(生成机器可识别代码)】:
  汇编阶段将汇编代码转换成机器可以直接识别的二进制代码(目标代码)。也就是把编译阶段生成的“.s”文件转成为“.o”的二进制目标代码。

实例:

 gcc -c hello.s -o hello.o
  • 这条命令会生成一个目标文件hello.o,它是二进制文件,但还不能直接执行;
  • hello.s 是要汇编的文件;
  • 选项“-o”,该选项的作用是让 gcc在预处理、编译、汇编后停止进行链接,生成二进制目标代码;
  • 选项“-o”指向目标文件hello.o;
  • hello.o文件为已经汇编后的目标文件。

✨【链接(生成可执行文件或库文件)】:
  在成功编译之后,就进入了链接阶段。链接阶段将目标代码与程序所需的库(如C标准库libc.so.6)合并,生成最终的可执行文件。

实例:

gcc hello.o -o hello
  • 这条命令将hello.o与必要的库链接,生成可执行文件hello。
  • hello.o 是要链接的文件;
  • 选项“-o”指向目标文件hello;
  • hello文件为已经链接后的目标文件。

通常情况下我们都是直接使用gcc hello.c -o hello命令来将.c源文件直接一次性生成最终的可执行文件。

3. 函数库

  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
  • 这是因为系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。

在编译过程中,程序可能会调用标准库或其他第三方库中的函数。这些函数的具体实现在库中,而编译时生成的目标文件仅包含对这些函数的引用。链接器(Linker)负责将这些引用与库中的实际实现关联起来。

库分为静态库和动态库两种

  • 静态库在编译时将库代码直接复制到可执行文件中,因此生成的可执行文件较大,但运行时不再需要库文件,其后缀名一般为“.a”。
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,由操作系统动态加载。这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。

4. 调试

  在Linux操作系统的软件开发中,调试是一个至关重要的环节。它帮助开发者定位和解决程序中的错误、优化代码性能以及深入理解程序的运行过程。Linux提供了GDB(GNU Debugger)作为强大的调试工具,可以帮助开发者在程序运行时查找和修复错误。

  GDB是GNU项目的一部分,是一款功能强大的程序调试工具,支持多种编程语言,包括C、C++、Ada等。它允许开发者在程序运行时暂停执行、检查程序的状态(如变量值、寄存器状态、内存内容等)、单步执行代码以及修改程序中的数据,从而帮助开发者定位问题所在。

  在Linux环境下,使用GCC(GNU Compiler Collection)或G++(GCC的C++编译器)编译程序时,可以选择不同的编译模式来优化程序或保留调试信息。这些模式主要包括debug模式和release模式。

  • Release模式

在Release模式下,编译器会进行各种优化,以减少程序的大小、提高运行速度和效率。这些优化可能包括代码重排、循环展开、内联函数等。在Release模式下编译的程序通常不包含调试信息,因此程序体积更小,运行更快,但更难进行调试。

  • Debug模式

Debug模式则相反,它主要是为了调试程序而设计的。在Debug模式下,编译器会生成包含大量调试信息的二进制文件,这些调试信息包括源代码的行号、变量名、函数名等,这些信息对于使用调试器(如GDB)来跟踪程序执行、检查变量值、设置断点等非常有用。

  • GCC/G++的-g选项

-g选项是GCC/G++编译器的一个非常关键的选项,它告诉编译器生成调试信息。默认情况下(即不指定-g选项时),GCC/G++会以类似于Release模式的方式编译程序,即进行优化但不包含调试信息。如果你想要使用GDB等调试工具来调试你的程序,你需要在编译时加上-g选项。这样,GCC/G++就会生成包含调试信息的二进制文件。例如:

g++ -g my_program.cpp -o my_program

这条命令会编译my_program.cpp文件,并生成一个名为my_program的二进制文件,该文件包含了调试信息,因此可以使用GDB进行调试。

总之,Linux gcc/g++出来的二进制程序,默认是release模式,要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项。

GDB的基本使用方法

首先可以使用sudo yum install -y gdb命令来安装gdb:

出现complete字样则表明安装成功🥳🥳

  1. 启动GDB

使用GDB调试程序非常简单,只需在命令行中输入gdb命令后跟程序名即可。例如,要调试名为test的程序,可以输入:

gdb test
  1. 设置断点

在GDB中,断点是最常用的功能之一。它允许程序在执行到特定行时暂停。可以通过break(简写为b)命令设置断点。例如,在程序第10行设置断点:

(gdb) b 10

或者,如果知道函数名,也可以直接在函数处设置断点:

(gdb) break main
  1. 查看断点

使用info breakpoints命令这是查看断点信息的最直接方式。在GDB命令行中输入info breakpoints(或简写为info b),GDB会列出所有已设置的断点信息,包括断点的编号、类型、是否启用、地址以及断点所在的源代码位置等。

(gdb) info b 

在这个示例中,Num是断点的编号,Type是断点的类型(这里是普通的断点),Disp是断点处理后的行为(keep表示断点保持活动状态),Enb表示断点是否启用(y表示启用),Address是断点所在的内存地址,What是断点所在的源代码位置。

如果你只对某个特定的断点感兴趣,可以使用info breakpoint 编号命令来查看该断点的详细信息。其中,“编号”是你想要查看的断点的编号。

(gdb) info breakpoint 1

这个命令会展示编号为1的断点的详细信息,与info breakpoints类似,但只针对这一个断点。

  1. 删除断点

delete 断点编号:删除指定编号的断点。
clear 文件名:行号:删除指定文件和行号上的断点。

此外:
disable breakpoints:禁用断点
enable breakpoints:启用断点

  1. 运行程序

设置好断点后,可以使用run(简写为r)命令启动程序。程序会在遇到第一个断点时暂停。

  1. 查看变量

查看变量值:使用print(简写为p)命令可以查看变量的当前值。例如,查看变量x的值:

(gdb) print x

display 变量名:跟踪查看一个变量,每次停下来都显示它的值
undisplay:取消对先前设置的那些变量的跟踪

  1. until X行号:跳至X行

  2. 查看调用栈

使用backtrace(简写为bt)命令可以查看当前的函数调用栈。

  1. 查看寄存器

通过info registers命令可以查看当前寄存器的状态。

  1. 单步执行

next(简写为n):执行下一行代码,如果当前行有函数调用,不会进入函数内部。
step(简写为s):执行下一行代码,如果当前行有函数调用,会进入函数内部。

  1. 继续执行

使用continue(简写为c)命令可以让程序继续执行,直到遇到下一个断点或程序结束。

  1. 执行到当前函数

finish:执行到当前函数返回,然后停下来等待命令

  1. 列出源码

list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
list/l 函数名:列出某个函数的源代码。


  1. 退出GDB

使用quit(简写为q)命令退出GDB。

GDB的高级技巧

  1. 条件断点

可以设置仅在特定条件下触发的断点。例如,当变量x等于10时暂停:

(gdb) break 10 if x == 10
  1. 观察点

与断点不同,观察点是在变量值发生变化时暂停程序。使用watch命令设置来观察变量的值:

(gdb) watch x
  1. 反汇编查看

使用disassemble(简写为disas)命令可以查看函数的汇编代码,有助于理解底层执行流程。

  1. 核心转储文件调试

当程序崩溃时,Linux系统会自动生成一个核心转储文件(core dump)。GDB可以加载这个文件进行调试,帮助开发者分析崩溃原因。

  1. 远程调试

GDB支持通过TCP/IP连接远程目标机进行调试,非常适合嵌入式系统或分布式系统的开发。

GDB作为一款功能强大的调试工具,为Linux环境下的软件开发提供了极大的便利。掌握GDB的基本使用方法和高级技巧,对于提升开发效率、保证软件质量具有重要意义。


5. 总结

  GCC是Linux下极其重要的编译器,通过gcc和g++,开发者可以方便地将C和C++源代码编译成可执行文件。了解GCC的编译过程和常用选项,对于Linux下的软件开发至关重要。此外通过GDB进行调试,可以进一步帮助开发者定位和解决程序中的错误。

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

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

相关文章

Mysql—主从复制的slave添加及延迟回放

MySQL 主从复制是什么? ​ MySQL 主从复制是指数据可以从一个 MySQL 数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,…

滑动窗口专题

通过以下几道题来熟悉滑动窗口 滑动窗口3大问题:如何移入窗口,如何移出窗口,如何更新答案 209. 长度最小的子数组 我们考虑通过窗口来计算和,快慢指针从左开始遍历。 移入窗口:直接把当前元素加进来。 移出窗口&am…

重大喜讯!科研界之大变革——“5分钟提交+24小时反馈”,投稿效率直线上升!

盘点允许“一稿多投”的SCI “一稿多投”一直被认为是学术不端的行为,但“禁止一稿多投”是纸质时代遗留下的产物,已不符合当今社会的发展。 一篇文章一审就是好几个月甚至是一两年,在科研圈子里都是平常事,每个科研人都曾深陷于…

乐道L60、MONA M03、理想L6,蔚小理围剿「特斯拉」

作者 |老缅 编辑 |德新 9月19日,蔚来全新品牌乐道首款车型——乐道L60正式上市,定位家庭智能电动SUV。 60kWh标准续航版,售价20.69万元85kWh长续航版,售价23.59万元;如果采用BaaS电池租用服务,则低至14.9…

如何在云端使用 Browserless 进行网页抓取?

云浏览器是什么? 云浏览器是一种基于云的组合,它将网页浏览器应用程序与一个虚拟化的容器相结合,实现了远程浏览器隔离的概念。开发人员可以使用流行的工具(如 Playwright 和​ Puppeteer​)来自动化网页浏览器&#…

cmake--list

教程 list--链接 list关键字的作用 list的操作 list追加字符串--APPEND set(str1 "aaaaaaaa") message(STATUS "str1${str1}") list(APPEND str1 "bbbb") message(STATUS "str1${str1}") list字符串拼接并不是直接拼接&#xff0c…

C# 用Timer控件简单写一个倒计时60s功能

先放界面上一个Label和一个Timer控件,Label用来展示倒计时秒数 添加事件 设置属性,设置每隔一秒执行一次 放代码: //设置时间控件开始运行,具体放在哪里看具体需求 this.timer1.Start();//定义一个全局变量表示秒数 int time…

在线版宣传册是如何制作的

​亲爱的创作者们,你是否想过将传统的纸质宣传册升级为更具吸引力的在线版?在这个数字化时代,在线版宣传册不仅能够节省印刷成本,还能让信息传递更加迅速、精准。今天,就让我们一起探索在线版宣传册的制作奥秘吧&#…

利用Mongoose库实现MQTT通信

Mongoose官方Github地址 官方对于Mongoose的简介: Mongoose - Embedded Web Server / Embedded Network Library Mongoose is a network library for C/C. It provides event-driven non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocol…

【吉林一号卫星简介】

吉林一号卫星 吉林一号卫星是中国长光卫星技术有限公司研制的遥感卫星,也是该公司在建的核心工程,是中国重要的光学遥感卫星星座。以下是对吉林一号卫星的详细介绍: 一、卫星概况 中文名:吉林一号外文名:Jilin 1 Bus…

视频汇聚EasyCVR视频监控平台调取接口提示“认证过期”是什么原因?

视频汇聚EasyCVR视频监控平台,作为一款智能视频监控综合管理平台,凭借其强大的视频融合汇聚能力和灵活的视频能力,在各行各业的应用中发挥着越来越重要的作用。EasyCVR平台具备强大的拓展性和灵活性,支持多种视频流的外部分发&…

丝杆支撑座许用条件的解析

丝杆支撑座连接滚珠丝杆使用能够支撑滚珠丝杆,使之更加平稳的运动,显著提高传动效率、降低噪音、提高精度、延长使用寿命等优势,是自动化设备中重要的传动元件。影响丝杆支撑座的因素主要包括轴承类型、润滑脂的使用、密封圈的保护、使用环境…

实现边框渐变效果

实现思路:定义一个具有相对定位、白色背景和透明边框的元素。边框宽度为3像素,并且有20像素的圆角。通过background-clip: padding-box;确保背景不会延伸到边框之外。 使用一个伪元素&::before来创建一个渐变边框。这个伪元素被放置在主元素的外部&…

Qt-QComboBox输入类控件(31)

目录 描述 核心方法 核心信号 使用 代码方式 界面操作方式 动态使用 如何看待输入输出 String与QString互相转化 描述 一个可以下拉的输入框 核心方法 addItem(constQString&)添加⼀个条⽬currentIndex()获取当前条⽬的下标 从0开始计算.如果当前没有条⽬被选中…

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题 最近两天更新了Xcode 16,然后正好要发布新版本的App,打包Adhoc没问题,但是上传AppStoreConnect或者TestFlight就不行解决方案参考资料 最近两天更新了Xcode 16,然后正好要发布新…

RegNet(CVPR2020):Designing Network Design Spaces,设计一个网络设计空间!

RegNet:Designing Network Design Spaces RegNet:设计一个网络设计空间 论文地址: https://arxiv.org/pdf/2003.13678 1、前言 在这项工作中,作者提出了一种新的网络设计范例。 作者的目标是帮助增进对网络设计的理解并发现跨设置…

【js逆向学习】酷我音乐排行榜 python+nodejs(webpack)

逆向目标 目标网址: https://www.kuwo.cn/rankList目标接口: https://www.kuwo.cn/api/www/bang/bang/musicList 加密参数: 参数一:secret参数二:reqId 逆向过程 老规矩先分析网络请求,我们可以分析到网络请求是通过ajax进行的&#xff…

【研赛E题成品论文】24华为杯数学建模研赛E题成品论文+可运行代码丨免费分享

2024华为杯研究生数学建模竞赛E题成品论文已出! E题 高速公路应急车道紧急启用模型 一、问题一模型建立与求解 1.1 问题一求解思路 赛题要求我们基于四个观测点的视频数据,提取交通流参数并分析这些参数随时间的变化规律。交通流参数包括:…

JAVA并发编程系列(11)线程池底层原理架构剖析

面试官:说说JAVA线程池的几个核心参数? 之前我们用了10篇文章详细剖析了synchronized、volatile、CAS、AQS、ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier、并发锁、Condition等各个核心基础原理,今天开始我们说说并发领域的各种…

ChatGLM-6B:部署指南与实战应用全解析

🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 SD3ComfyUI文生图部署步骤DAMODEL-ChatGLM-6B 服务端部署1.1、实例创建1.2、模型准备1.3、模型启动 SD3ComfyUI文生图部署步骤 Chat…