在linux上进行编译调试

1.相关疑问

1. 为什么在代码里使用了一个未定义过的函数(如add()),在编译阶段不会报错,在链接阶段会报错呢?

答:先说几个代码编译的结论:

  • 单个\.c源文件文件被编译成机器码文件时,源文件中的所有变量名以及数组名都会变成地址偏移量;
  • 类型信息都会变成指令的长度(int\-\>subl, 地址\-\>subg);
  • 循环会变成goto的方式实现;
  • 函数的调用变成了使pc指针移动到被调方函数的地址;

由以上第四条可知,函数的调用依赖于被调函数的地址,编译后的文件可以使用nm xxx.o来查看所有函数的地址和函数名的对应情况,在链接之前可以看到此时有的函数名还没有对应的地址,而将这些函数名和地址关联起来的操作就是链接阶段要做的事,在链接阶段无法为主调方找到被调方函数地址时就会报链接错误。
在这里插入图片描述

2. gcc编译器

1. 预处理指令

  • #include:引入头文件

  • #define:定义宏常量和宏函数

  • #if:根据指定条件判断是否编译后续代码块(可作为测试代码开关

    // 使用示例:
    #define DEBUG 1
    #if DEBUG// Debugging codeprintf("Debug mode is active.\n");
    #endif
    
  • #ifdef:判断某个标识符是否已经定义(可作为测试代码开关

    #ifdef ON //表示如果定义了ON,或命令行编译时用-D传了ON,就执行下面的输出printf("ON is defined!\n");
    #elseprintf("ON is not defined!\n");
    #endifprintf("main exit\n");
    

    可以在命令行定义预处理器宏gcc -o test test.c -DON

  • #ifndef:判断某个标识符是否没有已经定义(可用于头文件保护

    #ifndef TEST_H#define TEST_H
    #endif
    
  • #endif:结束条件编译的代码块

2. gcc常用指令

补充

列出所有函数:nm test.o

查看可执行程序链接了哪些库:ldd test

  • 预处理:

    gcc -E test.c -o test.i
    
  • 编译:

    gcc -S test.c -o test.s
    
  • 汇编:

    // 方式一:从汇编文件到机器码文件
    as test.s -o test.o
    // 方式二:从预处理文件到机器码文件
    gcc-13 -C test.i -o test.o
    // 方式三:从源文件到机器码文件
    gcc-13 -C test.c -o test.o
    
  • 链接:gcc -o test test.c 输出可执行文件

    // 方式一:编译+链接(从源文件到可执行文件)
    gcc -o test test.c
    // 方式二:链接
    gcc -o test test.o
    // 方式三:指定链接路径
    gcc test1.o -o test1 -ladd
    // 还可以使用ld命令可以调用静态链接器
    ld test.o [其他系统库文件] -o test
    
  • 定义宏:

    gcc test1.o -o test1 -D DEBUG
    
  • 制定优化级别:

    gcc test1.o -o test1 -O0 // 推荐O1级别
    
  • 为gdb补充符号信息:

    gcc test1.o -o test1 -O0 -g // 要用gdb调试时最好指定不优化,避免机器码和代码不一致影响调试
    
  • 提示警告:

    gcc test1.o -o test1 -Wall // 注意Wall是大写W
    
  • 指定头文件搜路径:

    gcc test1.o -o test1 -I "../h" //默认从当前路径下搜索
    

3. gdb调试

补充

用gdb调试时,传递命令行参数的两种方式:

  • 方式一:进入gdb后:用set args xxx
  • 方式二:进入gdb前:使用gdb --args test xxx启动

1. 常用指令

  1. 用-g生成可执行文件:gcc –o test test.c -O0 –g

  2. 进入调试器:gdb test

  3. 显示代码:

    • 默认显示:l/list //默认显示10行
    • 显示指定信息:l/list [文件名:]行号or函数名 //[]表示可有可无
  4. 运行:r/run

  5. 退出:q/quit

  6. 断点相关:

    • 设置断点:b/break 4 //在第四行设置断点
    • 列出断点:i b/info break // 查看断点号
    • 删除断点:delete 断点号
    • 停止断点:disable 断点号
    • 激活断点:enable 断点号
  7. 跳转:

    • 下一步不进入函数:n/next //F10
    • 下一步进入函数:s/step //F11
    • 到下一个断点:c/continue
    • 跳出当前函数:finsh
  8. 查看信息:

    • 打印变量:p/print
    • 自动显示的表达式内容:display 表达式 (自动显示内存:display /1xw &i``)
    • 停止显示某个表达式:undisplay 表达式 或者 undisplay 编号(通过info display查看编号)
    • 查看调用堆栈:b t/back trace
    • 查看内存:x<n/f/u> //n表示内存的长度 f表示内存的格式 u表示内存的单位
    • 清空信息: Ctrl + L 组合键,或者输入 shell clear 命令(shell命令用于调用系统断点shell

2. 调试core文件

  1. 启用 core 文件自动生成
    • 查看core文件是否存在限制:ulimit -a
    • 关闭限制:ulimit -c unlimited
  2. 运行程序并生成 core 文件
    • 如果未生成,则使用man core查看帮助文档解决;
  3. 使用 GDB 调试 core 文件:gdb test core;
  4. 查看调试信息
    • 查看调用栈:bt
    • 查看栈帧信息:frame 0
    • 显示寄存器的值:info registers
    • 分析内存:x

4. 静态库和动态库

库文件其实就是别人造好的“轮子”,别人写好并编译好后给用户使用的二进制代码。

静态库文件在程序的链接阶段被需要,而动态库文件在程序运行过程中也被需要。

1. 静态库

在程序链接阶段,库文件会被打包进最终的可执行程序。

gcc编译时,如果存在同名的动态(.so)和静态(.a)库文件,默认是使用动态文件,此时要使用静态库文件就必须要使用-static参数指定优先静态链接,如果找不对应的\.a文件会链接失败。

特点:省心,但体积大且更新不方便。

打包命令

// 1. 得到编译后的机器码文件
gcc -c add.c -o add.o 
// 2. 生成静态库文件(库文件必须以lib开头)
ar crsv libadd.a add.o
// 3. 将静态库文件移动到"/usr/lib"或"/usr/local/lib"下,推荐前者
sudo mv libadd.a /usr/lib
// 4. 使用即可
gcc main.o -o main -ladd

2. 动态库

链接阶段不打包进程序,在程序运行时加载。

特点:体积小、更新方便(动态更新),但容易存在依赖问题。

打包命令

// 1. 生成位置无关的目标代码,使用-fpid(Position Independent Code)
gcc -c add.c -o add.o -fpic
// 2. 生成动态库文件(库文件必须以lib开头)
gcc -shared add.o -o libadd.so
// 3. 将静态库文件移动到"/usr/lib"或"/usr/local/lib"下,推荐前者
sudo mv libadd.so /usr/lib
// 4. 使用即可
gcc main.o -o main -ladd

3. 产品动态更新

原理:利用版本号和软连接实现

  • 第一步:生成带版本好的.so动态库文件,如:libadd.so.0.0.0、libadd.so.0.1.0
  • 第二步:建立最新版本的软连接,sudo ln -s libadd.so.0.1.0 libadd.so

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

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

相关文章

LVS 工作模式

1、LVS DR模式 DR 模式是通过改写请求报文的目标 MAC 地址&#xff0c;将请求发给真实服务器的&#xff0c;而真实服务器响应后的处理结果直接返回给客户端用户。DR 模式可以极大的提高集群系统的伸缩性。但是要求调度器 LB 与真实服务器 RS 都有一块网卡连接到同一物理网段上…

Codeforces Round 785 C. Palindrome Basis

C. Palindrome Basis 题意 定义一个正整数 a a a 是回文的&#xff08;没有前导 0 0 0&#xff09;当且仅当&#xff1a; a a a 的十进制表示形式回文 给定一个正整数 n n n &#xff0c;求出将 n n n 拆分成若干个回文数之和的方案数 思路 这是一个经典模型&#xff0…

媒体邀约:怎么吸引总体目标受众?

新闻媒体影响力日益扩大。不论是公司、机构还是其他&#xff0c;都希望能够通过新闻媒体的曝光来吸引更多总体目标受众。要想真正吸引住总体目标受众并非易事&#xff0c;需要一定的方案和方法。下面我们就深入探究媒体邀约推广的真相&#xff0c;共享怎么吸引总体目标受众的方…

秋招面试—计算机网络安全

2021 计算机网络安全 1.Get 和 Post 的区别 get 用于获取数据&#xff0c;post用于提交数据&#xff1b; get 的缓存保存在浏览器和web服务器日志中&#xff1b; get 使用明文传输&#xff0c;post请求保存在请求体中&#xff1b; get 长度限制在2048以内 2.常见的HTTP请…

Android P 屏保和休眠相关知识

Android P添加屏保功能&#xff0c;如果休眠时间设定大于屏保时间&#xff0c;则先进入屏保&#xff0c;达到休眠时间后再进入休眠 需求&#xff1a; 添加屏幕互保开关&#xff0c;默认关闭。只保留时钟&#xff0c;可设定指针和数字、夜间模式。启用时间改多长时间无操作进入…

###C语言程序设计-----C语言学习(6)#

前言&#xff1a;感谢老铁的浏览&#xff0c;希望老铁可以一键三连加个关注&#xff0c;您的支持和鼓励是我前进的动力&#xff0c;后续会分享更多学习编程的内容。 一. 主干知识的学习 1. while语句 除了for语句以外&#xff0c;while语句也用于实现循环&#xff0c;而且它…

初识elasticsearch

一、了解ES 1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在GitHub搜索代码 在电商网站搜索商品 在百度搜索答案 在打车软件搜索附近的车 …

(七)for循环控制

文章目录 用法while的用法for的用法两者之间的联系可以相互等价用for改写while示例for和while的死循环怎么写for循环见怪不怪表达式1省略第一.三个表达式省略&#xff08;for 改 while&#xff09;全省略即死循环&#xff08;上面已介绍&#xff09; 用法 类比学习while语句 …

MySQL原理(一)架构组成(1)物理文件组成

目录 一、日志文件 1、错误日志 Error Log 1.1、作用&#xff1a; 1.2、开启关闭&#xff1a; 1.3、使用 2、二进制日志 Binary Log & Binary Log Index 2.1、作用&#xff1a; 2.2、开启关闭&#xff1a; 2.3、Binlog还有一些附加选项参数 &#xff08;1&#x…

江科大stm32学习笔记6——GPIO输入准备

一、按键消抖 由于按键内部使用的是机械式弹簧片&#xff0c;所以在按下和松开时会产生5~10ms的抖动&#xff0c;需要通过代码来进行消抖。 二、滤波电容 在电路中&#xff0c;如果见到一端接在电路中&#xff0c;一端接地的电容&#xff0c;则可以考虑它的作用为滤波电容&am…

linux -- 内存管理 -- 页面分配器

linux内存管理 为什么要了解linux内存管理 分配并使用内存&#xff0c;是内核程序与驱动程序中非常重要的一环。内存分配函数都依赖于内核中一个非常复杂而重要的组件 - 内存管理。 linux驱动程序不可避免要与内核中的内存管理模块打交道。 linux内存管理可以总体上分为两大…

MYSQL基本查询(CURD:创建、读取、更新、删除)

文章目录 前言一、Create1.全列插入2.指定列插入3.插入否则更新4.替换 二、Retrieve1.SELECT列2.WHERE条件3.结果排序4.筛选分页结果 三、Update四、Delete1.删除数据2.截断表 五、插入查询结果六、聚合函数 前言 操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型…

Unity中URP下额外灯角度衰减

文章目录 前言一、额外灯中聚光灯的角度衰减二、AngleAttenuation函数的传入参数1、参数&#xff1a;spotDirection.xyz2、_AdditionalLightsSpotDir3、参数&#xff1a;lightDirection4、参数&#xff1a;distanceAndSpotAttenuation.zw5、_AdditionalLightsAttenuation 三、A…

Spring Security关键之5张数据表与7张表 !!!

一、什么是认证和授权&#xff1a; 认证&#xff1a;系统提供的用于识别用户身份的功能&#xff0c;通常提供用户名和密码进行登录其实就是在进行认证&#xff0c;认证的目的是让系统知道你是谁。授权&#xff1a;用户认证成功后&#xff0c;需要为用户授权&#xff0c;其实就…

全连MGRE(OSPF)综合实验

一.要求 二.底层--所有节点拥有合法ip地址 r1: r2&#xff08;isp&#xff09;: r3: r4: r5: r6: 三.全网可达 r1: r3&#xff1a; r4: r5: r6: 四.构建全连的MGRE环境 R1-R3-R4 R1&#xff1a; r3: r4: R1-R5-R6 r1: r5: r6: 五.ospf配置 R1&#xff1a; r3: r4: r5: r6:…

Qt应用软件【串口篇】串口通信

文章目录 1.串口概述2.串口传输数据的基本原理电信号的传输过程 3.串口的几个概念数据位&#xff08;Data Bits&#xff09;奇偶校验位&#xff08;Parity Bit&#xff09;停止位&#xff08;Stop Bits&#xff09;流控制&#xff08;Flow Control&#xff09;波特率&#xff0…

142. 环形链表 II(力扣LeetCode)

文章目录 142. 环形链表 II题目描述解题思路判断链表是否有环如果有环&#xff0c;如何找到这个环的入口 c代码 142. 环形链表 II 题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个…

7.【SpringBoot3】项目部署、属性配置、多环境开发

文章目录 1. SpringBoot 项目部署2. 属性配置方式2.1 通过 cmd 命令行配置2.2 通过环境变量配置2.3 通过外部配置文件来配置 3. 多环境开发 Profiles3.1 多环境开发的单文件配置3.2 多环境开发的多文件配置3.3 多环境开发-分组 1. SpringBoot 项目部署 项目完成后&#xff0c;…

LLM大模型x知识图谱2024最新SOTA方案【附开源代码】

大模型LLM与知识图谱KG的结合可以充分发挥两者的优势&#xff0c;例如LLMs的通用知识和语言处理能力&#xff0c;以及KGs的结构化和准确性。这种结合不仅能够提升模型的知识处理能力&#xff0c;还能够在多个层面上优化模型的性能&#xff0c;更好地解决各种现实世界的问题&…

新火种AI|Taylor Swift不雅照被疯传!AI背后的隐患和危机引人深思...

作者&#xff1a;小岩 编辑&#xff1a;彩云 如今本就是一个信息爆炸的年代&#xff0c;再伴随2023年AI技术的井喷式发展&#xff0c;AI正在以迅雷不及掩耳之势渗透到我们生活的方方面面。不过&#xff0c;AI技术是一把双刃剑&#xff0c;我们在享受AI技术带来的便捷和实用的…