【Linux下的cpp】编译调试(gcc、g++、gdb)

news2024/9/27 7:23:34

【Linux下的cpp】编译调试(gcc、g++、gdb)

文章目录

  • 【Linux下的cpp】编译调试(gcc、g++、gdb)
    • 简述gcc、g++、gdb
    • 编译过程
    • g++ 编译参数
    • 命令行编译演练
      • 1、直接编译
      • 2、生成库文件并编译
        • 链接静态库并生成可执行文件
        • 链接动态库生成可执行文件
    • gdb调试器
      • 1. 常用调试命令参数
        • 常用命令演示
      • 2. gdb 切换线程
      • 3. gdb命令行调试演练

不管是从事何种语言开发,合适的IDE以及开发环境是必不可少的。

简述gcc、g++、gdb

相同点

  • GNU 项目:它们都是 GNU 项目的一部分,并且都是开源的。
  • 命令行工具:它们都是命令行工具,适用于 Unix/Linux 环境。
  • 开发工具链:它们都是开发工具链的一部分,用于编译和调试程序。

不同点

  • 功能:

    • gcc:主要用于编译 C 语言程序。
    gcc -o myprogram myprogram.c
    
    • g++:主要用于编译 C++ 语言程序。
    g++ -o myprogram myprogram.cpp
    
    • gdb:用于调试程序,而不是编译。
    gdb myprogram
    
  • 输入和输出:

    • gccg++:接受源代码文件(如 .c.cpp)并生成目标文件或可执行文件。
    • gdb:接受可执行文件,用于调试运行中的程序。

总结

  • gcc 是一个通用编译器,主要用于编译 C 语言代码。
  • g++ 是一个专门的编译器,主要用于编译 C++ 语言代码。
  • gdb 是一个调试器,用于调试 C、C++ 及其他语言编写的程序。

编译过程

编译单个c++文件:g++ test.cpp -o test

单次编译命令

预处理 -》 编译 -》 汇编 -》链接

# 预处理
# -E 指示编译器仅对输入文件进行预处理
# -o  指定输出文件(这里是test.i)
g++ -E test.cpp -o test.i		// 生成.i文件

# 编译
# -S 让g++在为C++代码生成汇编语言文件后停止编译
# g++ 产生的汇编语言文件的缺省扩展名是 .s
g++ -S test.i -o test.s

# 汇编
# -c 让g++把源代码编译为机器语言的目标代码(只编译,不链接)
g++ -c test.s -o test.o

# 链接
# 生成可执行文件
g++ test.o -o test

g++ 编译参数

  1. -g 编译带调试信息的可执行文件
# -g 选项告诉 GCC 产生能被 GNU 调试器GDB使用的调试信息,以调试程序。
# 产生带调试信息的可执行文件test
g++ -g test.cpp -o test
  1. -O[n] 优化源代码
## 所谓优化,例如省略掉代码中从未使用过的变量、直接将常量表达式用结果值代替等等,这些操作会缩减目标文件所包含的代码量,提高最终生成的可执行文件的运行效率。

# -O 选项告诉 g++ 对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。 -O2 选项告诉 g++ 产生尽可能小和尽可能快的代码。 如-O2,-O3,-On(n 常为0–3)
# -O 同时减小代码的长度和执行时间,其效果等价于-O1
# -O0 表示不做优化
# -O1 为默认优化
# -O2 除了完成-O1的优化之外,还进行一些额外的调整工作,如指令调整等。
# -O3 则包括循环展开和其他一些与处理特性相关的优化工作。
# 选项将使编译的速度比使用 -O 时慢, 但通常产生的代码执行速度会更快。

# 使用 -O2优化源代码,并输出可执行文件
g++ -O2 test.cpp
  1. -l | -L 指定库文件/ 指定库文件路径
# -l参数(小写)就是用来指定程序要链接的库,-l参数紧接着就是库名
# 在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接

# 链接glog库
g++ -lglog test.cpp

# 如果库文件没放在上面三个目录里,需要使用-L参数(大写)指定库文件所在目录
# -L参数跟着的是库文件所在的目录名

# 链接mytest库,libmytest.so在/home/bing/mytestlibfolder目录下
g++ -L/home/bing/mytestlibfolder -lmytest test.cpp
  1. -I 指定头文件搜索目录
# -I
# /usr/include目录一般是不用指定的,gcc知道去那里找,
#但是如果头文件不在/usr/icnclude里我们就要用-I参数指定了,
# 比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude 参数了,如果不加你会得到一个”xxxx.h: No such file or directory”的错误。
# -I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。上面我们提到的–cflags参数就是用来生成-I参数的。

g++ -I/myinclude test.cpp
  1. -W 打印警告信息
  2. -w 关闭警告信息
  3. -std=c++11 设置编译标准
  4. -o 指定输出文件名
  5. -c 只编译,不链接
  6. -D 定义宏

image-20240618182132673

命令行编译演练

1、直接编译

# 将 main.cpp src/Swap.cpp 编译为可执行文件
g++ main.cpp src/swap.cpp -Iinclude
# 运行a.out
./a.out

image-20240618210958060

2、生成库文件并编译

注意源文件list 可以放在g++之后,也可以放在命令行最后

链接静态库并生成可执行文件
  1. 简单生成静态库(-c则是编译选项)
    • 语法:g++ -c -o libpublic.a public.cpp
    • 包含头文件则添加-I相对路径
  2. 指定库:
    • -l+指定库名(即libxxxx.a中的xxxx)
    • -L指定库目录(即静态库文件放在哪里)
  3. 链接不带任何限制参数(-o的作用是指定名称,而非链接选项)
# 将需要用到的库编译成机器语言文件
# g++ 源文件 -c(转为机器语言) -I(头文件目录)
# 将生成swap.o
g++ swap.cpp -c -I../include

# 生成静态库swap.a(这里的lib是前缀,只要生成静态库都需要这个前缀)
ar rs libswap.a swap.o

# 将main.cpp编译为可执行的static_main
# g++ 源文件 -l指定库文件 -L指定库目录 -I指定头文件目录 -o 可执行文件名
g++ main.cpp -lswap -Lsrc -Iinclude -o static_main

image-20240618214558253

链接动态库生成可执行文件
  1. 制作动态库g++ -fPIC -shared -o lib库名.so 源代码文件清单
    • -fPIC -shared:表示制作动态库
  2. 使用动态库需要改变环境变量选项:
    1. echo $LD_LIBRARY_PATH:查看当前库环境变量
    2. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库所在目录的绝对路径
# 生成动态库libswap.so
g++ swap.cpp -I../include -fPIC -shared -o libswap.so

# 生成可执行文件
# g++ 源文件 -I头文件目录 -l库名 -L库目录 -o 指定程序名
g++ main.cpp -Iinclude -lswap -Lsrc -o dynamic_main

# 运行方法一,手动指定动态库目录和运行文件
# 执行动态库生成后的可执行文件
# =指定库目录  可执行文件
LD_LIBRARY_PATH=src ./dynamic_main

# 运行方法二:将动态库所在目录加入系统的动态库环境变量中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库所在目录的绝对路径

gdb调试器

gdb调试器是Linux下系统开发C/C++最常用的调试器。

Tips:

  1. 编译程序时需要加上-g,之后才能用gdb进行调试:g++ -g main.cpp -o main

  2. 回车键:重复上一命令

1. 常用调试命令参数

调试开始:执行gdb [exefilename] ,进入gdb调试程序,其中exefilename为要调试的可执行文件名

## 以下命令后括号内为命令的简化使用,比如run(r),直接输入命令 r 就代表命令run

$(gdb)help(h)	# 查看命令帮助,具体命令查询在gdb中输入help + 命令

$(gdb)run(r)	# 重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件)

$(gdb)start		# 单步执行,运行程序,停在第一行执行语句

$(gdb)list(l) 	# 查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数)

$(gdb)set		# 设置变量的值,如:1. set args a b c (当main函数带参时); 2. 改变内部变量的值 set var name = "aaa"

$(gdb)next(n)   # 单步调试(逐过程,函数直接执行)

$(gdb)step(s)	# 单步调试(逐语句:跳入自定义函数内部执行)

$(gdb)backtrace(bt)	# 查看函数的调用的栈帧和层级关系

$(gdb)frame(f) 	# 切换函数的栈帧

$(gdb)info(i) 	# 查看函数内部局部变量的数值

$(gdb)finish	# 结束当前函数,返回到函数调用点

$(gdb)continue(c)	# 继续运行

$(gdb)print(p)	# 打印值及地址

$(gdb)quit(q) 	# 退出gdb

$(gdb)break+num(b)			# 在第num行设置断点, b20行设置断点

$(gdb)info breakpoints		# 查看当前设置的所有断点

$(gdb)delete breakpoints num(d)	# 删除第num个断点

$(gdb)display				# 追踪查看具体变量值

$(gdb)undisplay				# 取消追踪观察变量

$(gdb)watch					# 被设置观察点的变量发生修改时,打印显示

$(gdb)i watch				# 显示观察点

$(gdb)enable breakpoints	# 启用断点

$(gdb)disable breakpoints	# 禁用断点

$(gdb)x						# 查看内存x/20xw 显示20个单元,16进制,4字节每单元

$(gdb)run argv[1] argv[2]	# 调试时命令行传参

$(gdb)set follow-fork-mode child#Makefile项目管理:选择跟踪父子进程(fork())
常用命令演示
# 启动调试可执行文件
rdjroot@TM:~/Coding/cppnet$ gdb server

# 设置main函数的入参,第一个可执行文件已省略
(gdb) set args 5005

# 设置跟踪文件
(gdb) file ~/Coding/cppnet/server
# 展示90行左右的代码
(gdb) list 90

# 设置断点在88行
(gdb) b 88

# start开始执行,会在main函数前停止,直到continue.
# run会直接执行
(gdb) start

# 设置监视变量(公式)
(gdb) display eventfd

# 删除监视变量
(gdb) undisplay 1(这里是变量的id或者变量名)

# 显示所有的监视变量
(gdb) info display

# 退出调试
(gdb) quit

2. gdb 切换线程

常用的 thread 命令示例:

  1. info threads:显示当前程序中所有线程的信息,包括线程号和调用堆栈。

  2. thread <thread-id>:切换到指定线程。您可以使用线程号或者线程索引(从0开始)来切换到相应的线程。

  3. info inferiors:显示所有程序执行实例的信息,每个实例对应一个线程组。

  4. thread apply <thread-id-list> <gdb-command>:对指定线程列表执行命令。例如,thread apply 1 2 3 bt将对线程1、2和3依次执行 bt 命令(打印调用堆栈)。

通过这些命令,您可以方便地管理和调试多线程程序。

3. gdb命令行调试演练

使用gdb命令打开用-g生成的可执行文件,进行调试

image-20240619215604801

4、gdb调试core文件

  1. 修改core限制
# 查看系统限制参数
ulimit -a 
# 修改core问价大小为無限
ulimit -c unlimited
  1. 再次启用运行程序,如果出错会产生core.xxx文件
  2. 调试core文件:gdb core.xxx runexe。->进入gdb命令界面,会显示错误行数
  3. bt查看函数调用栈

5、调试正在运行的程序

  1. 使用命令查看正在执行程序的进程编号:ps -ef | grep run_exe

image-20240701193421469

  1. gdb run_exe -p process_num - > 会使正在运行的程序暂停

修改core限制

# 查看系统限制参数
ulimit -a 
# 修改core问价大小为無限
ulimit -c unlimited
  1. 再次启用运行程序,如果出错会产生core.xxx文件
  2. 调试core文件:gdb core.xxx runexe。->进入gdb命令界面,会显示错误行数
  3. bt查看函数调用栈

5、调试正在运行的程序

  1. 使用命令查看正在执行程序的进程编号:ps -ef | grep run_exe

[外链图片转存中…(img-5Md3n8KT-1726372189697)]

  1. gdb run_exe -p process_num - > 会使正在运行的程序暂停

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

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

相关文章

vue vueUse利用useInfiniteScroll API 实现虚拟滚动

前言 中文网地址:开始使用 | VueUse 中文网 官网地址:VueUse 元素的无限滚动。 useInfiniteScroll 详细解析地址 效果 组件封装

7-14 电话聊天狂人(map)

输入样例: 4 13005711862 13588625832 13505711862 13088625832 13588625832 18087925832 15005713862 13588625832输出样例: 13588625832 3 代码&#xff1a; #include<iostream> #include<map> using namespace std; map<string,int>mp; string ansstr;…

华为OD机试 - 推荐多样性(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

nginx负载均衡(轮询与权重)

文章目录 1. nginx的介绍2. nginx使用场景3. nginx在windows的下载与安装4. nginx的简单使用5. nginx进行轮询测试6. nginx进行权重测试7. 总结 1. nginx的介绍 Nginx&#xff08;engine x&#xff09;是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也是一个开源的、…

PASCAL VOC数据集语义分割:解决标签值错误与数据增强不同步问题的优化方案

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 错误原因分析&#xff1a; Assertion错误&#xff1a; 错误信息显示 Assertion t > 0 && t < n_classes failed.&#xff0c;这意味着在计算损失时&#xff0c;标签t的值不…

第四天旅游线路预览——从换乘中心到喀纳斯湖

第四天&#xff1a;从贾登峪到喀纳斯风景区入口&#xff0c;晚上住宿贾登峪&#xff1b; 换乘中心有4 路车&#xff0c;喀纳斯①号车&#xff0c;去喀纳斯湖&#xff0c;路程时长约5分钟&#xff1b; 将上面的的行程安排进行动态展示&#xff0c;具体步骤见”Google earth stu…

【devops】devops-git之github使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

继承和多态(详解)

&#x1f423;继承和多态 &#x1f31e; 继承&#x1f33b;1.引入&#x1f33b;2.访问父类成员&#x1f335;2.1 子类访问父类中的成员变量&#x1f335;2.2 子类访问父类中的成员方法 &#x1f33b;3.super关键字&#x1f33b;4.子类构造方法&#x1f33b;5.super和this&#…

java spring validation 自动、手动校验

目录 一、自动校验 第一步&#xff0c;导入依赖 第二步&#xff0c;统一异常处理 第三步&#xff0c;定义接口接收实体DTO 第四步&#xff0c;在Contoller接口中增加参数注解Validated 第五步&#xff0c;测试结果 二、手动校验 第一步&#xff0c;校验工具类 第二步&…

Protubuf入门

⼀、初识 ProtoBuf 1. 序列化概念 序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程 称为对象的序列化。 反序列化&#xff1a;把字节序列恢复为对象的过程 称为对象的反序列化。 什么情况下需要序列化 存储数据&#xff1a;当你想把的内存中的对象状态…

Spring Boot环境下的读书笔记交流网络

第2章 技术介绍 2.1B/S架构 当向其他用户发送请求的功能时应用B/S模式具有独一无二的优点&#xff1a;用户请求通过网络向其他Web服务器发送时只需要通过浏览器就可以实现该功能。该功能的好处之一就是有效简化了客户端&#xff0c;大部分开发的软件只需要用浏览器即可&#xf…

QT Mode/View之View

目录 概念 使用已存在的视图 使用模型 使用模型的多个视图 处理元素的选择 视图间共享选择 概念 在模型/视图架构中&#xff0c;视图从模型中获取数据项并将它们呈现给用户。数据的表示方式不必与模型提供的数据表示形式相似&#xff0c;而且可能与用于存储数据项的底层数…

【重学 MySQL】二十四、笛卡尔积的错误和正确的多表查询

【重学 MySQL】二十四、笛卡尔积的错误和正确的多表查询 笛卡尔积的理解和错误笛卡尔积的理解定义例子在数据库中的应用总结 笛卡尔积的错误 正确的多表查询使用 INNER JOIN使用 WHERE 子句&#xff08;隐式内连接&#xff09; 总结 在数据库查询中&#xff0c;特别是涉及到多表…

【python计算机视觉编程——9.图像分割】

python计算机视觉编程——9.图像分割 9.图像分割9.1 图割安装Graphviz下一步&#xff1a;正文9.1.1 从图像创建图9.1.2 用户交互式分割 9.2 利用聚类进行分割9.3 变分法 9.图像分割 9.1 图割 可以选择不装Graphviz&#xff0c;因为原本觉得是要用&#xff0c;后面发现好像用不…

大模型教程:使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用

vLLM 是一个简单易用的 LLM 推理服务库。加州大学伯克利分校于 2024 年 7 月将 vLLM 作为孵化项目正式捐赠给 LF AI & Data Foundation 基金会。欢迎 vLLM 加入 LF AI & Data 大家庭&#xff01;&#x1f389; 在主流的 AI 应用架构中&#xff0c;大语言模型&#xff…

数据清洗-缺失值处理-缺失值可视化图(竖线)

目录 一、安装所需的python包二、缺失值可视化分析2.1 可直接运行代码2.2 以某个缺失值数据进行可视化实战2.2.1 代码运行过程截屏&#xff1a;2.2.2 缺失图可视化&#xff1a; 感觉大家对原理性的东西不太感兴趣&#xff0c;那我就直接举例提供代码&#xff0c;以及详细的注释…

13、Python如何设置文件缓冲

什么是I/O操作&#xff0c;看一下百度百科的说法&#xff1a;I/O操作是指对设备与cpu连接的接口电路的操作&#xff0c;不是对外围设备直接进行操作。宏观上讲&#xff0c;I/O是信息处理系统&#xff08;例如计算机&#xff09;与外部世界&#xff08;可能是人或其他信息处理系…

Flutter之SystemChrome全局设置

一、简介 SystemChrome作为一个全局属性&#xff0c;很像 Android 的 Application&#xff0c;功能很强大。 二、使用详解 2.1 setPreferredOrientations 设置屏幕方向 在我们日常应用中可能会需要设置横竖屏或锁定单方向屏幕等不同要求&#xff0c;通过 setPreferredOrien…

阿里云镜像报错 [Errno 14] HTTP Error 302 - Found 问题解决记录

1、问题背景和解决思路 在本地安装 CentOS7 后&#xff0c;网络已调通可正常上网&#xff0c;但切换阿里云镜像后&#xff0c;使用 yum 安装软件时出现 “[Errno 14] HTTPS Error 302 - Found Trying other mirror.” 报错&#xff0c;原因是 yum 源配置问题。给出了详细的解决…

分布式可信认证:数据安全与隐私保护新范式

文章目录 前言一、可信数字身份成数据要素流通的关键二、分布式可信认证成数据安全与隐私保护新范式1、分布式可信认证很好地解决传统数字身份认证的痛点问题2、可信数字身份上升为国家战略三、安全是未来数字身份的基础1、有效的威胁建模策略是确保这些系统安全性的基石前言 …