C++(Qt)软件调试---GCC编译参数学习-程序检测(13)

news2025/5/25 13:10:47

C++(Qt)软件调试—GCC编译参数学习-程序检测(13)

文章目录

  • C++(Qt)软件调试---GCC编译参数学习-程序检测(13)
    • 1、前言
      • 1.1 概述
      • 1.2 测试环境
    • 2、GCC编译警告选项
      • 1.1 编译警告的作用
      • 1.2 GCC常用的编译警告选项
    • 3、GCC程序检测选项
      • 1.1 性能分析选项(-pg)
      • 1.2 运行检测(-fsanitize)
        • 1.1.1 fsanitize=address
        • 1.1.2 fsanitize=thread
        • 1.1.3 fsanitize=leak
        • 1.1.4 fsanitize=undefined
    • 4、总结

更多精彩内容
👉个人内容分类汇总 👈
👉C++软件调试、异常定位 👈

1、前言

1.1 概述

  • 在前面学习了C++常用编译器(MSVC、GCC、MinGW)的一些常用的编译器参数,主要是用于【预处理】、【编译】、【优化】、【调试】等方面的选项/参数,有助于我们优化程序性能或者调试软件bug;
  • 而我们常说的编译器其实并不是一个软件,而是一套强大的编译器工具集。
  • 在本章内会学习GCC编译器的【警告选项】、【程序检测选项】,从静态、动态两方面检测、调试我们的程序,提高软件质量,减少bug数量。

1.2 测试环境

g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0

2、GCC编译警告选项

  • 详细用法

1.1 编译警告的作用

编译器警告是指在编译源代码时,编译器检测到可能存在问题或潜在错误时发出的警告信息(不会影响程序编译)。

这些警告信息可以帮助开发人员识别潜在的bug、不良的编程习惯以及代码中的一些不规范之处,从而帮助开发人员改善代码质量。

  • 潜在错误检测: 编译器警告能够识别一些可能导致程序运行错误的代码模式,例如未初始化的变量、不兼容的数据类型转换等。
  • 代码质量提升: 警告信息可以帮助开发人员识别代码中的一些不良习惯,如未使用的变量、无用的代码、冗余的操作等,从而改善代码的可维护性和可读性。
  • 可移植性增强: 编译器警告还可以帮助开发人员遵循语言规范和标准,以确保代码在不同的编译器和平台上都能正确地编译和执行。

所以:在开发中还是不要忽略警告信息。

1.2 GCC常用的编译警告选项

  1. -w:禁止所有警告消息。

  2. -Wall: 启用所有常见的警告信息,需要注意的是,虽然-Wall选项会开启很多常见的警告,但并不一定涵盖所有可能的问题。有时候,特定项目的要求可能需要更严格的警告设置或者其他编译选项的结合使用。

  3. -Wextra: 启用一组额外的警告检查,这些警告通常不会被启用,即使使用了-Wall选项(开启大部分常见的警告)。这个选项允许编译器检查更多的代码模式,以帮助开发人员捕获更多潜在问题。。

  4. -Werror: 将警告视为错误,编译时如果有警告会导致编译失败

  5. -Wpedantic: 在编译C和C++代码时启用严格的警告,以便检测出与语言标准不一致的代码。这个选项会提示可能违反C和C++标准的代码,以帮助开发者编写更加规范和可移植的代码。

  6. -Wunused: 报告未使用的变量、参数等警告;

    • 由很多子项组成,部分子项包含在-Wall -Wextra中了。
    • 如果要检测函数参数未使用,需要单独指定-Wextra或者-Wunused-parameter
    • 对于全局变量、成员变量未使用检测不到。
    #include <iostream>
    
    using namespace std;
    
    class Test{
    
    public:
        Test()
        {
        }
        int m_c;
    private:
        int m_a;
        int* m_b;
    };
    
    int g_b;
    
    void fun(int v)
    {
        cout << "fun" << endl;
    }
    
    int main()
    {
        Test t;
        fun(123);
        int a;
        int b;
        int *c;
    
        return 0;
    }
    
  7. -Wuninitialized: 报告使用了未初始化的变量,但是这个功能基本只对未初始化的局部变量生效,由于全局变量、成员变量的复杂性,检测不是很准确(在-Wall中包含)。

    • 测试时使用纯C++编写测试代码,使用命令行编译会检测到成员编译(但不全),在Qt中检测不到。
    #include <iostream>
    
    using namespace std;
    
    class Test{
    
    public:
        Test()
        {
    	cout << m_a << endl;
            cout << m_b << endl;
        }
    private:
        int m_a;
        int* m_b;
    };
    
    int g_b;
    
    int main()
    {
        Test t;
        int a;
        int b;
        int *c;
        cout << a << endl;
        cout << b << endl;
        cout << c << endl;
        cout << g_b << endl;
        return 0;
    }
    
  8. -Wconversion: 报告隐式类型转换警告,如果用到库,则可能会出现很多警告,例如Qt开发。

    • 隐式类型转换可能导致数据截断或溢出、精度损失、不正确的值、内存访问问题等后果;
    double d = 10;
    int a = d;                        // double类型转int 
    uint ui = 10;
    
    if(ui > a)                       // 无符号和有符号比较会隐式类型转换
    {
        qDebug() << "int uint";
    }
    
  9. -Wformat: 检查printfscanf格式字符串的问题(在-Wall中包含)。

  10. -Wshadow: 用来检测变量名的遮蔽(shadowing)问题的,遮蔽问题指的是在嵌套作用域中,内部作用域的变量名与外部作用域的变量名相同,可能导致程序逻辑错误或混淆。

    int a = 10;
    if(true)
    {
        int a = 20;
    }
    
  11. -Wcast-qual: 报告指针类型转换时丢失了限定符(const、volatile)的警告。例如:

    const char* a = new char[10];
    char* b= (char*)a;
    
  • 演示

在这里插入图片描述

3、GCC程序检测选项

  • GCC官方文档

1.1 性能分析选项(-pg)

软件的性能是软件质量的重要考察点,不论是在线服务程序还是离线程序,甚至是终端应用,性能都是用户体验的关键。再好的程序、在牛掰的功能算法如果性能不满足要求,占用资源过高也是失败的。

  • -p / -pg: gcc 中的一个编译选项,用于在生成的可执行文件中插入性能分析代码,以便进行性能分析和 profiling(性能剖析)。以帮助开发人员了解程序的运行时间分布、函数调用关系以及性能瓶颈,从而指导优化工作。需要注意的是,由于插入了额外的代码,使用 -pg 选项可能会稍微影响程序的执行速度,因此在进行性能分析时需要权衡是否使用该选项。

使用方式

  1. 在程序编译链接时使用-pg选项,会在程序中插入性能分析代码,编译后的程序会大一些;
    • g++ -pg main.cpp
  2. 编译后的程序会在运行时收集函数调用信息和计时数据。运行程序后,会生成 gmon.out 文件,其中包含了运行时收集的数据;(注意,没执行到的函数不会进行分析)
  3. 使用gprof命令来分析记录程序运行信息的gmon.out文件。
    • gprof [options] a.out gmon.out > outfile 将分析结果输出到outfile文件中;
    • [options]为gprof的命令选项,可省略,可通过gprof -h命令查看可用参数;
    • 其中包含了函数调用图、函数执行时间、调用次数等信息。

gprof说明

  • 一种用于分析程序性能的工具,它能够生成函数级别的性能分析报告,帮助开发人员找出程序中的瓶颈和性能问题。gprof 通常与 GNU 编译器集合中的 gcc 配合使用,它通过在程序中插入一些特殊的代码来收集运行时的函数调用信息,然后生成性能分析报告。

  • gprof官方文档

  • 示例

    在这里插入图片描述

1.2 运行检测(-fsanitize)

GCC的-fsanitize选项用于在编译的程序运行时进行检测,主要有下列功能:

1.1.1 fsanitize=address

  • -fsanitize=address:使用 AddressSanitizer(ASan)C/C++的内存错误检测器,它可以检测内存访问错误,如堆栈缓冲区溢出、堆区越界等;编译指令:g++ -g -fsanitize=address main.cpp

    • GCC版本:4.8+
    • AddressSanitizer(ASan)是一种用于检测和调试内存错误的工具。它是由Google开发的,并内置于GNU编译器套件(GCC)和LLVM编译器中。
  • 注意:如果编译时不加-g,则在显示的信息中可能无法定位到具体位置。

    1. 释放后使用(野指针)

      #include <iostream>
      
      using namespace std;
      
      int main()
      {
          int* arr = new int[10];
          delete[] arr;
       //   arr[1] = 123;                   // 写入错误可检测
          cout << arr[1] << endl;           // 读取错误可检测
          return 0;
      }
      

      在这里插入图片描述

    2. 堆缓冲区溢出

      #include <iostream>
      
      using namespace std;
      
      int main()
      {
          int* arr = new int[10];
          arr[1] = 123;
          cout << arr[10] << endl;
          delete[] arr;
          return 0;
      }
      
      

      在这里插入图片描述

    3. 栈缓冲区溢出

      #include <iostream>
      
      using namespace std;
      
      int main()
      {
          int arr[10];
          arr[1] = 123;
          cout << arr[10] << endl;
          
          return 0;
      }
      

      在这里插入图片描述

    4. 全局缓冲区溢出

      #include <iostream>
      
      using namespace std;
      
      int g_arr[10] = {0};
      int main()
      {
          g_arr[1] = 123;
          cout << g_arr[10] << endl;
          
          return 0;
      }
      

      在这里插入图片描述

    5. 返回局部堆区地址后使用(经过测试没检测出来)

      #include <iostream>
      
      using namespace std;
      
      int* g_p = nullptr;
      void fun()
      {
          int arr[10];
          g_p = arr;
      }
      int main()
      {
          fun();
          cout << g_p << endl;
          cout << g_p[1] << endl;
          
          return 0;
      }
      
    6. 作用域外使用栈内存

      #include <iostream>
      
      using namespace std;
      
      int main()
      {
          int* p = nullptr;
          {
      	    int a = 10;        // 离开大括号作用域后就被释放了
      	    p = &a;
          }
          *p = 20;               // 使用不在作用域的栈内存
          cout << *p << endl;
          return 0;
      }
      

      在这里插入图片描述

    7. 初始化顺序错误(经过测试未检测出来)

      // 1.cpp
      #include <iostream>
      using namespace std;
      
      extern int extern_global;
      int __attribute__((noinline)) read_extern_global() 
      {
        return extern_global;
      }
      int x = read_extern_global() + 1;
      
      int main() 
      {
        cout << x << endl;
        return 0;
      }
      
      // 2.cpp
      int foo() 
      { 
          return 42; 
      }
      int extern_global = foo();
      
      • 由于编译时指定1.cpp和2.cpp的顺序不同会导致初始化顺序不同,得到的输出结果也会不同;

      在这里插入图片描述

    8. 内存泄漏

      #include <iostream>
      
      using namespace std;
      
      
      void fun()
      {
          int* a = new int();
      }
      
      int main()
      {
          fun();
          return 0;
      }
      

      在这里插入图片描述

1.1.2 fsanitize=thread

  • -fsanitize=thread:使用 ThreadSanitizer(TSan)工具,它可以检测多线程程序中的数据竞争和其他线程相关的错误。数据争用是并发系统中最常见和最难调试的错误类型之一。当两个线程同时访问同一变量并且至少有一个访问是写入时,就会发生数据争用。

    • 注意:不能和-fsanitize=address -fsanitize=leak 一起使用。
    #include <iostream>
    #include <thread>
    using namespace std;
    
    int g_a = 0;
    
    // 在线程中修改全局变量
    void fun1() 
    {
        for(int i = 0; i < 10; i++)
        {
            g_a++;
    	cout << g_a << endl;
        }
    }
    
    int main() 
    {
        // 创建两个线程
        thread t1(fun1);
        thread t2(fun1);
    
        // 等待新线程结束
        t1.join(); 
        t2.join();
    
        return 0;
    }
    
    
    • 编译:g++ -g -fsanitize=thread -lpthread main.cpp
    • 可能会出现报错:/usr/bin/ld: 找不到 libtsan_preinit.o: 没有那个文件或目录

    在这里插入图片描述

1.1.3 fsanitize=leak

  • -fsanitize=leak:使用 LeakSanitizer(LSan)工具,它可以检测程序中的内存泄漏。

    #include <iostream>
    
    using namespace std;
    
    
    void fun()
    {
        int* a = new int();
    }
    
    int main()
    {
        fun();
        return 0;
    }
    

    在这里插入图片描述

1.1.4 fsanitize=undefined

  • -fsanitize=undefined:使用 UndefinedBehaviorSanitizer(UBSan)工具,它可以检测代码中的未定义行为,如除以零、空指针解引用等。

    • 由于未定义行为很多,这里就例举了3种进行演示;
    #include <iostream>
    #include <limits.h>
    using namespace std;
    
    int main()
    {
        int arr[10];
        cout << arr[-1] << endl;     // 数组越界
    
        int a = INT_MAX;
        unsigned int b = a + 1;      // 溢出
    
        int c = 0;
        int d = a / c;              // 除0
        return 0;
    }
    
    

    在这里插入图片描述

4、总结

  • GCC编译选项就是非常非常的多,功能非常强大,这里只是介绍了常用的一些功能选项,值得花一些时间去研究一下;
  • 我们软件开发并不只是单纯的编写代码哦。

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

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

相关文章

解决Agora声网音视频在后台没有声音的问题

前言:本文会介绍 Android 与 iOS 两个平台的处理方式 一、Android高版本在应用退到后台时,系统为了省电会限制应用的后台活动,因此我们需要开启一个前台服务,在前台服务中发送常驻任务栏通知,以此来保证App 退到后台时不会被限制活动. 前台服务代码如下: package com.notify…

在ubuntu安装vncserver,可以打开远程桌面

1.网上查找vncserver的资料 2.在ubuntu20.04上面使用 https://www.5axxw.com/questions/simple/ywnpl5 参考了这个和其他很多 我直接运行vncserver&#xff0c;没有成功&#xff01; 当我使用这个命令时 xtigervncviewer -SecurityTypes VncAuth -passwd /home/yx/.vnc/passw…

构建高效的接口自动化测试框架思路

在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选择哪种框架&#xff0c;重要的是确保 框架功能完备&#xff0c;易于维护和扩展&#xff0c;提高测试效率和准确性。今…

Biome-BGC生态系统模型与Python融合技术教程

详情点击公众号链接&#xff1a;Biome-BGC生态系统模型与Python融合技术教程 前言 Biome-BGC是利用站点描述数据、气象数据和植被生理生态参数&#xff0c;模拟日尺度碳、水和氮通量的有效模型&#xff0c;其研究的空间尺度可以从点尺度扩展到陆地生态系统。 在Biome-BGC模型…

crm、scrm、ocrm、acrm、ccrm等等分别是什么?有什么区别?

crm、SCRM、OCRM、ACRM、CCRM等等分别是什么&#xff1f;crm&#xff0c;scrm&#xff0c;ocrm&#xff0c;acrm&#xff0c;ccrm有什么区别&#xff1f;又有什么联系&#xff1f;这些系统各自之间都有哪些优势和缺点呢&#xff1f;今天将带领大家深入浅出的系统了解crm&#x…

idea 创建java web项目 run后出现404现象

1、创建新项目 创建的新项目只是单纯的java项目&#xff0c;如图 2、添加lib库文件&#xff0c;里面存放jar包&#xff0c;并导入库配置 这里要注意&#xff0c;需要先添加lib库文件再去配置模块和工件否则会出现404现象 3、打开模块设置&#xff0c;设置项目配置 将本…

c语言练习58:⾃定义类型:结构体

⾃定义类型&#xff1a;结构体 结构体的概念 结构是⼀些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 结构体是一个种自定义的数据类型&#xff0c;它可以由很多个默认数据类型组成。它主要用于描述复杂场景下的变量。 例如&#xff0c;想…

go语言基础--杂谈

常量运行期间&#xff0c;不可以改变的值 const PI float64 3.14字面常量 所谓字面常量&#xff0c;是值程序中硬编码的常量 123 //整型类型常量 156.78 //浮点类型的常量 true //布尔类型的常量 “abc”//字符串类型的常量//const PI float64 3.14 const PI 3.14 // //P…

在Kubernetes集群中部署 dolphindcheduler-3.1.8

温故知新 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的&#x1f4d7;总体方向 &#x1f4da;第二章 部署&#x1f4d7;安装helm&#x1f4d7;安装dolphindcheduler&#xff08;使用k8s的部署用户操作&#xff09;&#x1f4d5;通过命令验证&#x1f4d5;通过Ku…

OpenCV(四十二):Harris角点检测

1.Harris角点介绍 什么是角点&#xff1f; 角点指的是两条边的交点&#xff0c;图中红色圈起来的点就是角点。 Harris角点检测原理&#xff1a;首先定义一个矩形区域&#xff0c;然后将这个矩形区域放置在我的图像中&#xff0c;求取这个区域内所有的像素值之和&#xff0c;之…

【C语言】每日一题(半月斩)——day2

目录 一.选择题 1、以下程序段的输出结果是( ) 2、若有以下程序&#xff0c;则运行后的输出结果是&#xff08; &#xff09; 3、如下函数的 f(1) 的值为&#xff08; &#xff09; 4、下面3段程序代码的效果一样吗( ) 5、对于下面的说法&#xff0c;正确的是&#xf…

2024CFA一级notes百度网盘下载

024CFA一级notes百度网盘下载 2024CFA一级notes2024年CFA考纲已经正式发布&#xff0c;相比与老考纲&#xff0c;新考纲变化实在不算小。 面对2024年CFA新考纲的变化&#xff0c;我们在第一时间对2024年考试的新趋势和新变化&#xff0c;进行深度解读。具体总结如下&#xff…

ddtrace 系列篇之 dd-trace-java 项目编译

dd-trace-java 是 Datadog 开源的 java APM 框架&#xff0c;本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要&#xff1a;jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常&#xf…

短视频搭建矩阵源码--短视频矩阵源码搭建

短视频矩阵系统是一种通过将短视频内容进行分类、管理和展示的系统。它可以将用户上传或者选择的短视频按照不同的特定标签进行分类和管理&#xff0c;用户可以根据自己的兴趣和需求选择观看不同类别的短视频。 短视频矩阵源码的开发部署其实并不难&#xff0c;主要依托于抖音平…

springboot集成excel导入导出

1、引入依赖 <dependency><groupId>com.pig4cloud.excel</groupId><artifactId>excel-spring-boot-starter</artifactId><version>1.2.7</version> </dependency> 2、导出 ResponseExcel(name "测试列表") Post…

记录:移动设备软件开发(activity组件)

目录 前言Android简介和发展Android应用的基本组件介绍Activity组件Activity简介Activity的状态和生命周期 小结 前言 移动设备软件开发是指为智能手机、平板电脑等移动设备设计和开发应用程序的过程。移动设备软件开发涉及多种技术、平台和工具&#xff0c;例如Android、iOS、…

R语言CalibrationCurves包绘制带可信区间的校准曲线

校准曲线图表示的是预测值和实际值的差距&#xff0c;作为预测模型的重要部分&#xff0c;目前很多函数能绘制校准曲线。 一般分为两种&#xff0c;一种是通过Hosmer-Lemeshow检验&#xff0c;把P值分为10等分&#xff0c;求出每等分的预测值和实际值的差距。一种是绘制连续的校…

C#: 未能加载文件或程序集“xxx“

导入数据时&#xff0c;发生了异常&#xff0c;错误日志如下&#xff1a; 2023-09-11 09:20:49,304 [125] FATAL [(null)] - NPOI.POIXMLException ---> System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.IO.FileLoadException: 未能加…

OpenCV之GOTURN目标追踪

&#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 目录 前言 一、goturn简介 二、预处理 三、模型加载 四、执行推理 五、解…

干洗店洗鞋店小程序家政保洁带商城一体化系统开发

干洗店洗鞋店小程序家政保洁带商城一体化系统开发&#xff1b; 一、核心功能介绍 1.(支持上门取送、送货到店、寄存网点、智能衣柜四种下单方式) 用户下单-上门取货拍照-送达门店工厂-入厂拍照-清洗完成拍照-上挂物品柜-物品送回 2.骑手端(接单上门、取货拍照&#xff0c;入库拍…