【嵌入式】嵌入式系统稳定性建设:静态代码扫描的稳定性提升术

1. 概述

在嵌入式系统开发过程中,代码的稳定性和可靠性至关重要。静态代码扫描工具作为一种自动化的代码质量检查手段,能够帮助开发者在编译前发现潜在的缺陷和错误,从而增强系统的稳定性。本文将介绍如何在嵌入式C/C++开发中使用静态代码扫描工具,并通过示例代码展示其应用效果。

文章目录

  • 1. 概述
  • 2. 静态代码扫描工具简介
  • 3. 使用静态代码扫描工具的步骤
    • 3.1 选择合适的静态代码扫描工具
    • 3.2 配置扫描工具
    • 3.3 集成到开发流程中
    • 3.4 分析和修复问题
  • 4. cppcheck功能演示
    • 4.1 问题代码
    • 4.2 问题1:数组越界
    • 4.3 问题2:变量未初始化val
    • 4.4 问题3:申请的内存未释放
    • 4.5 修复后的代码
  • 5. 总结
  • 6. 高阶玩法

2. 静态代码扫描工具简介

静态代码扫描工具通过对源代码进行静态分析,检查代码中的语法错误、逻辑错误、安全漏洞等问题,并给出相应的警告或错误提示。这些工具可以集成到开发流程中,作为代码提交前的自动检查手段,帮助开发者及时发现问题并进行修复。

3. 使用静态代码扫描工具的步骤

3.1 选择合适的静态代码扫描工具

根据项目的需求和团队的偏好,选择一款适合嵌入式C/C++开发的静态代码扫描工具。常见的工具有Cppcheck、PCLint、Coverity等。

3.2 配置扫描工具

根据不同工具的文档,配置扫描规则、扫描范围等参数,确保工具能够针对项目的特点进行准确的扫描。

3.3 集成到开发流程中

将静态代码扫描工具集成到开发流程中,如持续集成/持续部署(CI/CD)系统中,实现自动化的代码质量检查。这个话题并非本文的核心,后面将使用单独文章来进行讨论。

3.4 分析和修复问题

定期运行扫描工具,分析扫描结果,并根据提示修复代码中的问题。

4. cppcheck功能演示

本文以cppeheck(Ubuntu上的安装命令:sudo apt-get install cppcheck)为例演示静态代码扫描的过程和结果展示。其它工具留待大家自行实验以比较各自的优缺点。

4.1 问题代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int exampleFunction()
{printf("%s enter\n", __func__);int array[10];int index = 10;array[index] = 42; // 数组越界访问printf("%s leave\n", __func__);return 0;
}int exampleFunction1()
{int value; // 变量未初始化printf("%s enter\n", __func__);if (value == 0) {printf("value is 0");} else {printf("value not 0");}printf("%s leave\n", __func__);return 0;
}int exampleFunction2()
{char *buffer = NULL;printf("%s enter\n", __func__);buffer = malloc(10); //buffer申请的内存没有释放strcpy(buffer, "haha");printf("%s leave\n", __func__);return 0;
}int main(int argc, char *argv[])
{exampleFunction();exampleFunction1();exampleFunction2();return 0;
}

如上所示,代码包含了三个函数:exampleFunctionexampleFunction1exampleFunction2,以及一个 main函数来调用它们。
下面是该程序编译运行的结果:
在这里插入图片描述
可以发现,该程序运行过程中出现了异常,被终止运行了。

实际上,这3个函数每一个函数都有其独特的问题,这些问题就可以通过静态代码扫描工具在编译前发现。下面我将逐一解释每个函数的问题,并展示cppcheck扫描到的结果。

4.2 问题1:数组越界

exampleFunction这个函数试图访问数组 array 的第 11 个元素(索引为 10),但是 array 实际上只有 10 个元素(索引从 09)。这是一个典型的数组越界访问错误

使用cppcheck静态代码扫描工具进行扫描,会得到类似以下的扫描结果:
在这里插入图片描述
结果清晰命令:[example.c:11]: (error) Array 'array[10]' accessed at index 10, which is out of bounds.,翻译过来就是:example.c的11行存在错误:数组array试图访问下标为10的数组元素,这超出了数组的边界

根据扫描结果的提示,我们应该修复数组越界访问的问题。修复方案如下:

  1. 确保数组索引在有效范围内。
  2. 如果需要访问数组的最后一个元素,使用sizeof(array) / sizeof(array[0]) - 1来计算最后一个有效索引。

4.3 问题2:变量未初始化val

exampleFunction1这个函数声明了一个整数变量value,但没有初始化它。然后它检查value是否等于 0,但由于value是未初始化的,这个检查是未定义的,因为它可能包含任何随机值,也就是每次运行可能会进入if分支,也可能会引入else分支,完全是一个随机事件。

使用cppcheck静态代码扫描工具进行扫描,会得到类似以下的扫描结果:
在这里插入图片描述
结果清晰命令:[example.c:24]: (error) Uninitialized variable: value,翻译过来就是:example.c的24行存在错误:未初始化变量:value

根据扫描结果的提示,我们应该修复变量未初始化的问题。修复方案如下:

  1. 在定义所有变量时,确保对其进行初始化。

4.4 问题3:申请的内存未释放

exampleFunction2这个函数分配了10字节的内存给buffer,然后尝试将字符串 "haha"(包括一个终止符 ‘\0’ 总共 5 个字符)复制到buffer中。函数在退出前没有释放分配的内存,导致出现了内存泄漏。

使用cppcheck静态代码扫描工具进行扫描,会得到类似以下的扫描结果:
在这里插入图片描述
结果清晰命令:[example.c:46]: (error) Memory leak: buffer,翻译过来就是:example.c的46行存在错误:内存泄漏:value

根据扫描结果的提示,我们应该修复变量未初始化的问题。修复方案如下:

  1. 确保在不再需要内存时使用free函数释放它。

4.5 修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int exampleFunction()
{printf("%s enter\n", __func__);int array[10];int index = sizeof(array) / sizeof(array[0]) - 1;array[index] = 42; // 数组越界访问,已经修复printf("%s leave\n", __func__);return 0;
}int exampleFunction1()
{int value = 0; // 变量未初始化,已经修复printf("%s enter\n", __func__);if (value == 0) {printf("value is 0");} else {printf("value not 0");}printf("%s leave\n", __func__);return 0;
}int exampleFunction2()
{char *buffer = NULL;printf("%s enter\n", __func__);buffer = malloc(10); //buffer申请的内存没有释放,已经修复strcpy(buffer, "haha");free(buffer);printf("%s leave\n", __func__);return 0;
}int main(int argc, char *argv[])
{exampleFunction();exampleFunction1();exampleFunction2();return 0;
}

修复后的代码,编译运行结果如下所示,可以看到,所有函数正常执行,使用valgrind检测,也没有内存泄漏了。
在这里插入图片描述

5. 总结

静态代码扫描工具是嵌入式C/C++开发中不可或缺的一部分,它能够帮助开发者及时发现并修复代码中的潜在问题,提高系统的稳定性和可靠性。

6. 高阶玩法

通过集成静态代码扫描工具到开发流程中,并定期对代码进行扫描和修复,我们可以有效地提升嵌入式系统的质量。

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

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

相关文章

c#空闲中断接收

C# 28.实现串口空闲中断接收功能_c# serialport空闲中断-CSDN博客

Spring Boot 整合 Redis 实现排行榜功能

在Spring Boot中整合Redis实现排行榜功能,你首先需要在项目中添加Redis的依赖,并配置好Redis连接信息。然后,你可以使用Spring Data Redis提供的模板类来操作Redis的有序集合(Sorted Set),从而实现排行榜功能。 以下是使用Spring Boot整合Redis实现排行榜功能的基本步骤:…

Spring Boot启动流程详解

Spring Boot是一个基于Spring框架的快速开发工具&#xff0c;它可以帮助我们快速搭建一个可运行的Spring应用。本文将详细介绍Spring Boot的启动流程&#xff0c;帮助大家更好地理解Spring Boot的工作原理。 一、Spring Boot启动流程概述 Spring Boot的启动流程可以分为以下几…

排序算法——梳理总结

✨冒泡 ✨选择 ✨插入  ✨标准写法  &#x1f3ad;不同写法 ✨希尔排序——标准写法 ✨快排 ✨归并 ✨堆排 ✨冒泡 void Bubble(vector<int>& nums) {// 冒泡排序只能先确定最右边的结果&#xff0c;不能先确定最左边的结果for (int i 0; i < nums.size(); i){…

基于深度学习的交通标志检测识别系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 添加注意力机制&#xff08;SE、CBAM等&#xff09;         2. 修改可变形卷积&#xff08;DySnake-主干c…

linux系统命令深入研究1——ls的参数

ls list命令有一些常用的参数&#xff0c;其中-a意为列出all全部文件&#xff08;包括隐藏文件&#xff09;&#xff0c;-l列出详细信息&#xff0c;-h以人类可阅读的方式列出文件大小 --full-time是列出详细时间信息&#xff0c;包括最后一次修改时间 -t是按时间排序&#xff…

课时57:数组实践_综合实践_数组案例

1.2.2 数组案例 学习目标 这一节&#xff0c;我们从 信息统计、服务管理、小结 三个方面来学习。 信息统计 需求 分别打印CPU 1min 5min 15min load负载值 命令提示&#xff1a;uptime信息显示&#xff1a;CPU 1 min平均负载为: 0.00CPU 5 min平均负载为: 0.01CPU 15 min平…

Git 内幕探索:从底层文件系统到历史编辑的全面指南

微信搜索“好朋友乐平”关注公众号。 1. Git 底层文件对象 #mermaid-svg-uTkvyr26fNmajZ3n {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-uTkvyr26fNmajZ3n .error-icon{fill:#552222;}#mermaid-svg-uTkvyr26fNmaj…

Spark实战-基于Spark日志清洗与数据统计以及Zeppelin使用

Saprk-日志实战 一、用户行为日志 1.概念 用户每次访问网站时所有的行为日志(访问、浏览、搜索、点击)用户行为轨迹&#xff0c;流量日志2.原因 分析日志&#xff1a;网站页面访问量网站的粘性推荐3.生产渠道 (1)Nginx(2)Ajax4.日志内容 日志数据内容&#xff1a;1.访问的…

每天学习一个Linux命令之chown

每天学习一个Linux命令之chown 在Linux系统中&#xff0c;chown命令用于更改文件或目录的所有者。通常情况下&#xff0c;只有超级用户root和文件所有者本人可以使用chown命令。在这篇博客中&#xff0c;我们将详细介绍chown命令的用法以及所有可用的选项。 1. 命令格式 bas…

【动态规划】完全背包

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f449;&#x1f3fb;完全背包 &#x1f449;&#x1f3fb;…

政安晨:【深度学习处理实践】(二)—— 最大汇聚运算

最大汇聚运算&#xff08;Max Pooling Operation&#xff09;是深度学习领域卷积神经网络常用的一种汇聚运算方式。在卷积神经网络中&#xff0c;经过一系列卷积层和激活函数层后&#xff0c;数据在空间尺寸上逐渐减小&#xff0c;特征图的深度也逐渐增加。为了降低数据尺寸并提…

微信小程序(五十三)修改用户头像与昵称

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.外界面个人资料基本模块 2.资料修改界面同步问题实现&#xff08;细节挺多&#xff0c;考虑了后期转服务器端的方便之处&#xff09; 源码&#xff1a; app.json {"window": {},"usingCompone…

算法打卡day11|栈与队列篇03|Leetcode 239. 滑动窗口最大值、347.前 K 个高频元素

小顶堆和大顶堆 小顶堆&#xff08;Min Heap&#xff09;和大顶堆&#xff08;Max Heap&#xff09;是两种特殊的完全二叉树&#xff0c;它们遵循特定的堆属性&#xff0c;即父节点的值总是小于或等于&#xff08;小顶堆&#xff09;或者大于或等于&#xff08;大顶堆&#xf…

Spring AOP相关注解及执行顺序

Aspect&#xff08;切面&#xff09;&#xff1a;用于标识一个类是切面的注解。通常与其他通知注解一起使用&#xff0c;定义切面类。 Pointcut&#xff08;切点&#xff09;&#xff1a; 注解来定义切点&#xff0c;它用于描述哪些连接点将会被通知所通知。 连接点&#xff…

Linux minfo命令教程:详解MS-DOS文件系统参数查看命令(附实例详解和注意事项)

Linux minfo命令介绍 minfo命令用于显示MS-DOS文件系统的各项参数&#xff0c;如磁区数、磁头数和柱面数等。它还可以打印一个mformat命令行&#xff0c;该命令行可以用于在其他媒体上创建类似的MS-DOS文件系统。 Linux minfo命令适用的Linux版本 minfo命令在大多数Linux发行…

算法D39 | 动态规划2 | 62.不同路径 63. 不同路径 II

今天开始逐渐有 dp的感觉了&#xff0c;题目不多&#xff0c;就两个 不同路径&#xff0c;可以好好研究一下 62.不同路径 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流&#xff0c;很难想到。 代码随想录 视频讲解&#xff1a;动态规划中如何初始化很重要&#x…

Latex公式太长换行标号

Latex中公式太长换行&#xff0c;且编号&#xff0c;可以采用align&#xff0c;不编号行公式用\nonumber&#xff0c;示例如下&#xff1a; \begin{align}\nonumber %第1行公式不编号&abababababababa\\&cdm %第2行公式编号 \end{align}效果如下 原文件链接 公式不…

清除Mac OS上Xcode占用的空间

最近自己的Mac OS存储空间严重不足&#xff0c;想了一下&#xff0c;大概是从安装 Xcode 之后出现&#xff0c;在系统下通过 du 命令分析各目录大小&#xff0c;发现大概下面几个目录占用空间比较大&#xff0c;所以针对这几个名目录作了一下清理&#xff0c;释放了几十个G的空…

Leetcode 268 火星词典

题目描述&#xff1a; 现有一种使用英语字母的火星语言&#xff0c;这门语言的字母顺序与英语顺序不同。 给你一个字符串列表 words &#xff0c;作为这门语言的词典&#xff0c;words 中的字符串已经 按这门新语言的字母顺序进行了排序 。 请你根据该词典还原出此语言中已知…