MISRA 2012学习笔记(1)-Directives
文章目录
- 说明
- Directives
- 2 编译与构建
- Dir 2.1
- 3 需求可追溯性
- Dir 3.1
- 4 代码设计
- Dir 4.1
- Dir 4.2
- Dir 4.3
- Dir 4.4
- Dir 4.5
- Dir 4.6
- Dir 4.7
- Dir 4.8
- Dir 4.9
- Dir 4.10
- Dir 4.11
- Dir 4.12
- Dir 4.13
说明
以下等级一般分为三种,建议,必要,强制
建议:建议准则应该在合理可行的范围内遵循这些条目。建议准则不需要正式偏差授权
必要:声明符合本文件的 C 代码应符合所有必要准则,如果有不符合项,则应如第 5.4 节所述,有正式的偏差声明。
强制:声明符合本文档的C 代码应符合每项强制准则,且不允许有偏离。
Directives
2 编译与构建
Dir 2.1
所有源文件都应通过编译且没有任何编译错误
等级:该指令必要被执行
原理:有的编译器可能会尽管编译错误,但仍会生成目标模块。但是,执行生成的程序可能会产生意外的行为。
3 需求可追溯性
Dir 3.1
所有代码应可追溯到书面要求
等级:该指令必要被执行
原理:所有的程序代码都应该是项目功能需要的,例如开发员人debug时的代码应该在量产时被删除,否则可能导致输出异常,影响其他控制器。
追溯代码到文件化要求的方法应由项目决定。 一种实现可追溯性的方法是对照相应的已针对需求进行审核过的设计文档来审核代码。
4 代码设计
Dir 4.1
运行时的故障,应尽量减少
等级:该指令必要被执行
原理:C 语言设计提供非常有限的内置的运行时检查。虽然这种方法可以生成紧凑而快速的可执行代码,但是它将运行时检查的负担放在了程序员身上。因此,为了达到预期的健壮性水平,程序员必须仔细考虑在可能发生运行时错误的地方添加动态检查。
运行时故障一般包括以下可能:
◆ 算术错误:这包括在表达式求值中出现的错误,例如上溢,下溢,被零除或因移位而丢失有效位。 在考虑整数溢出时,请注意,无符号整数计算不会严格溢出,而是会产生确定的值,但可能是意料之外的值。 应仔细考虑算术表达式中的值范围和运算顺序。该项在编写程序时时常需要注意
◆ 指针算术:确保在动态计算地址时,计算出的地址是合理的,并且指向有意义的地方。特别需要确保的是,如果一个指针指向数组中的某个点,那么当指针被增加或以其他方式改变时,它仍然指向同一个数组中的某个点。参见指针算法的限制—Rule 18.1、Rule 18.2 和 Rule 18.3。
◆ 数组超限错误:在使用数组索引对数组进行索引之前,请确保数组索引在数组大小的范围内—Rule 18.1。该项在编写程序时时常需要注意
◆ 函数参数:在将参数传递给库函数(Dir 4.11)之前,应检查其有效性
◆ 指针引用:除非指针已知为非 NULL,否则在引用指针之前应进行运行时检查。一旦进行了检查,在单个函数中推断指针是否已经更改以及是否需要另一个检查就相对简单了。跨函数边界进行推理要困难得多,特别是在调用其他源文件或库中定义的函数时。
◆ dynamic memory 动态存储:如果正在执行动态内存分配,则必须检查每个分配是否成功,并且设计并测试了适当的降级或恢复策略
Dir 4.2
汇编语言的所有运用都应记录在案
等级:该指令建议被执行
原理:应该记录使用汇编语言的基本原理以及 C 和汇编语言之间的接口连接机制。
Dir 4.3
汇编语言应被封装和隔离
等级:该指令必要被执行
原理:使用汇编语言说明的地方,应将它们封装和隔离在下述结构中:
◆ 汇编语言函数;
◆ C 语言函数(C99 首选内联函数);
◆ C 语言宏。
出于执行效率的考虑,有时必须嵌入简单的汇编指令,例如启用/禁用中断。若有必要(嵌入汇编指令), 则建议使用宏或内联函数(C99)来实现。
封装汇编语言的益处:
◆ 提高可读性;
◆ 封装宏或函数的名称和文档,清楚地说明了汇编指令的意图;
◆ 所有执行相同指定功能的汇编语言代码可以共享相同的封装,从而提高可维护性;
◆ 当实现方案或静态分析变动时,封装后的汇编语言可以轻松的被替换。
注意:内联汇编语言的使用是对标准C 的扩展,因此它违反了 Rule 1.2。
Dir 4.4
代码段不应被“注释掉”
等级:该指令建议被执行
原理:代码中的未参与编译的部分应该使用条件编译实现,例如:
#if 0
...
#endif
Dir 4.5
具有相同可见性的相同名称空间中的标识符在印刷/屏幕显示上应明确
等级:该指令建议被执行
原理:同一段代码中的相同名称空间下列字符不能同时存在于两个变量中:
大写与小写,如id2_abc与id2_ABC不要同时存在
带下划线与不带下划线,如 id1_a_b_c与id1_abc
字母“ O”和数字“ 0”,如id6_O和id6_0
字母“ I”和数字“ 1”,如id4_I和 id4_1
字母“ I”和字母“ l”,如id4_I和id4_l
字母“ l”和数字“ 1”,如id4_l和 id4_1
字母“ S”和数字“ 5”,如id4_S和 id4_5
字母“ Z”和数字“ 2”,如id5_Z和 id5_2
字母“ n”和字母“ h”,如id5_n和 id5_h
字母“ B”和数字“ 8”,如id7_B和 id7_8
字母序列“ rn”(“ r”后跟“ n”)和字母“ m”,如id8_rn和 id8_m
int32_t id9_rn;
struct
{int32_t id9_m; /* Compliant(这里合规,是因为它和上面的 id9_rn 不是同一命名空间) */
};
Dir 4.6
应使用指示大小和符号的 typedef 类型代替基本数字类型
等级:该指令建议被执行
基本数字类型(char,short,int,long,long long(C99),float,double 和long double)不应被使
用,而应使用由 typedef 定义的特定长度的数字类型。
原理:这个实际代码中使用的很多,autosar标准数据type中也有定义,如unsigned char被typedef为uint8
Dir 4.7
如果函数返回错误信息,则应测试该错误信息
等级:该指令必要被执行
使用:一个函数(无论它是标准库的一部分,第三方库还是用户定义的功能)都可以视为提供了一些指示错误发生的方法。 这可以通过错误标志,某些特殊的返回值或其他方式进行。 每当函数提供这种机制时,调用程序应在函数返回后立即检查错误指示。
但是,请注意,检查函数的输入值被认为是比在函数完成后尝试检测错误更可靠的错误预防方法(请参见Dir 4.11)。
Dir 4.8
如果指向结构体或联合的指针在转换单元中从未解引用,则应该隐藏该对象的实现
等级:该指令建议被执行
原理:在使用结构体或联合体时,如果没有进行解引用,即访问内部的数据定义,则应该通过指针操作.
示例:
/* Opaque.h */
#ifndef OPAQUE_H
#define OPAQUE_H
typedef struct OpaqueType *pOpaqueType;
#endif
/* Opaque.c */
#include "Opaque.h"
struct OpaqueType
{/* Object implementation */
};
/* UseOpaque.c */
#include "Opaque.h"
void f ( void )
{pOpaqueType pObject;pObject = GetObject ( ); /* Get a handle to an OpaqueType object */UseObject ( pObject ); /* Use it... */
}
在C文件中进行具体的结构体/联合体的定义,在头文件通过指针定义该数据类型。实际访问时不会访问具体的内部数据,保证内部数据不会被意外修改。
Dir 4.9
应该优先使用函数而不是类函数的宏,因为它们是可互换的
等级:该指令建议被执行
原理:在大多数情况下,应该使用函数而不是宏。函数执行参数类型检查并对其参数求值一次,从而避免了潜在的多重副作用问题。在许多调试系统中,步进执行函数比步进执行宏更容易。
尽管如此,宏在某些情况下可能是有用的。
在决定使用函数还是宏时应考虑下述因素:
•函数参数和结果类型检查的好处;
•C99中内联函数的可用性,尽管注意内联函数的作用程度是由实现定义的;
•代码大小和执行速度之间的权衡
•编译时求值的可能性是否重要:带有常量参数的宏更有可能在编译时求值,而不是相应的函数调用;
•参数是否对函数有效:宏参数是文本的,而函数参数是表达式;
•易于理解和可维护性
示例:
以下示例符合标准。 这些类似函数的宏不能用函数替换,因为它具有 C 操作符作为参数:
#define EVAL_BINOP( OP, L, R ) ( ( L ) OP ( R ) )
uint32_t x = EVAL_BINOP ( +, 1, 2 );
在下面的示例中,使用宏初始化具有静态存储持续时间的对象是合规的,因为此处不允许进行函数调用。
#define DIV2(X) ( ( X ) / 2 )
void f ( void )
{static uint16_t x = DIV2 ( 10 ); /* 合规 - 此处不允许函数调用 */uint16_t y = DIV2 ( 10 ); /* 违规 - 此处允许函数调用 */
}
Dir 4.10
应采取预防措施,以防止头文件的内容被包含多次
等级:该指令必要被执行
原理:这个也很常见,在头文件中需要“头文件卫士”
示例:
/* file.h */
#ifndef FILE_H
/* 违规 - 缺少 #define FILE_H */
#endif
为了便于检查,应使用下列两种形式之一,对头文件的内容进行保护,避免多次包含。
<start-of-file>
#if !defined ( identifier )
#define identifier/* Contents of file */
#endif
<end-of-file>
<start-of-file>
#ifndef identifier
#define identifier/* Contents of file */
#endif
<end-of-file>
Dir 4.11
应该检查传递给库函数的值的有效性
等级:该指令必要被执行
原理:标准库中的许多函数都不检查传递给它们的参数的有效性。而且,即使标准中要求进行检查,或编译器作者声称检查参数的情况下,也不能保证进行充分的检查。
类似地,其他库中的函数的接口描述可能不会指定这些函数执行的检查。还有一个风险是,指定的检查不一定充分执行。
编程人员应为所有具有限制输入域的库函数(标准库、第三方库和内部库)提供适当的输入值检查。
标准库中具有受限域并需要检查的函数示例如下:
•<math.h>中的许多数学函数,例如:
- 负数不能传递给sqrt或log函数;
- fmod的第二个参数不能为零
•当函数 toupper 传递一个非小写字母的参数(tolower 也有一样的问题)时,某些实现可能会产生意外结果;
•如果传递无效值,<ctype.h>中的字符测试函数会显示未定义的行为;
•应用于最负整数的abs函数给出了未定义的行为
尽管<math.h>中的大多数数学库函数定义了允许的输入域,但是当发生域错误时,它们返回的值可能因编译器而异。因此,预先检查输入值的有效性对这些函数尤为重要
编程人员应该识别任何领域约束,这些约束应该合理地应用于正在使用的函数(可能在接口描述中记录,也可能没有记录),并提供适当的检查,以确保输入值位于该域中。当然,如果需要,可以通过了解参数表示的内容以及参数值的合理范围来进一步限制该值
我们可以通过多种方式来满足本准则的要求,包括:
•在调用函数之前检查值;
•检查调用的库函数中的值——这尤其适用于内部设计的库,但如果供应商能够证明他们已经内置了检查,则可以适用于购买的库;
•生成执行检查的函数的“包装”版本,然后调用原始函数;
•静态地演示输入参数永远不能取无效值
Dir 4.12
不应使用动态内存分配
等级:该指令必要被执行
此规则适用于所有的动态内存分配的封装,包括:
◆ 标准库提供的内容;
◆ 第三方软件包。
原理:标准库的动态内存分配和释放例程可能导致规则21.3中描述的未定义行为。任何其他动态内存分配系统都可能表现出与标准库类似的未定义行为。
应检查第三方例程的规范,以确保动态内存分配没有被无意中使用
如果决定使用动态内存,应注意确保软件以可预测的方式运行。例如,存在以下风险:
•可用内存可能不足以满足请求-必须注意确保对分配失败有一个安全和适当的响应
•根据使用模式和产生的碎片程度,执行分配或重新分配所需的执行时间差异很大
示例:
为了方便起见,这些示例都是基于使用标准库的动态内存函数,因为它们的接口是众所周知的
在本例中,在第一次调用free之后,由于指针p的值变得不确定,因此该行为是未定义的。尽管在调用free之后存储在指针中的值保持不变,但在某些目标上,它所指向的内存可能不再存在,并且复制该指针的行为可能导致内存异常
#include <stdlib.h>
void f ( void )
{char *p = ( char * ) malloc ( 10 );char *q;free ( p );q = p; /* Undefined behaviour - value of p is indeterminate */p = ( char * ) malloc ( 20 );free ( p );p = NULL; /* Assigning NULL to freed pointer makes it determinate */
}
如果要使用malloc,必须要保证释放后的指针为NULL
Dir 4.13
为对资源提供操作而设计的函数应该按适当的顺序调用
等级:该指令建议被执行
在资源上提供操作的一组函数通常有三种操作:
- 分配资源,例如打开文件;
- 资源的释放,例如关闭文件;
- 其他操作,例如从文件中读取。
对于每一组这样的函数,对其操作的所有使用都应按适当的顺序进行。
原理:静态分析器工具能够提供路径分析检查,可以通过程序识别导致未调用序列的释放函数的路径。为了使这种自动检查的好处最大化,因此鼓励开发人员通过设计和声明静态分析器的平衡函数集来启用这些检查。
示例:
/* These functions are intended to be paired */
extern mutex_t mutex_lock ( void );
extern void mutex_unlock ( mutex_t m );
extern int16_t x;
void f ( void )
{mutex_t m = mutex_lock ( );if ( x > 0 ){mutex_unlock ( m );}else{/* Mutex not unlocked on this path */}
}
加锁和解锁需要按顺序调用
相关文章:

MISRA 2012学习笔记(1)-Directives
文章目录 说明Directives2 编译与构建Dir 2.1 3 需求可追溯性Dir 3.1 4 代码设计Dir 4.1Dir 4.2Dir 4.3Dir 4.4Dir 4.5Dir 4.6Dir 4.7Dir 4.8Dir 4.9Dir 4.10Dir 4.11Dir 4.12Dir 4.13 说明 以下等级一般分为三种,建议,必要,强制 建议&#…...

升级node版本后vue2的项目node-sass、sass-loader安装报错(14.x升级到16.x)
node升级到16.x版本后,对应的node-sass需要升级到^6.0.0,此时sass-loader的版本需要升级到10.2.0以上 ,具体对应版本规则可参考链接: https://github.com/webpack-contrib/sass-loader/releases?page3 vue2通过vue/cli创建的项目࿰…...

深入理解CSS选择器:选择正确的方式掌控样式与布局
文章目录 CSS 概括CSS 选择器元素选择器(Element Selector)类选择器(Class Selector)ID 选择器(ID Selector)通用选择器(Universal Selector)属性选择器(Attribute Selec…...

qt设置控件的风格样式
设置tablewidget ui.tableWidget_MaterialLibrary->setStyleSheet("QTableView {""color:#DCDCDC;""background-color: #444444;""border: 1px solid #242424;""alternate-background-color:#525252;""gridline-co…...

简单易懂的Transformer学习笔记
1. 整体概述 2. Encoder 2.1 Embedding 2.2 位置编码 2.2.1 为什么需要位置编码 2.2.2 位置编码公式 2.2.3 为什么位置编码可行 2.3 注意力机制 2.3.1 基本注意力机制 2.3.2 在Trm中是如何操作的 2.3.3 多头注意力机制 2.4 残差网络 2.5 Batch Normal & Layer Narmal 2.…...

C语言经典小游戏之三子棋(超详解释+源码)
“纵有疾风来,人生不言弃,风乍起,合当奋意向此生。” 今天我们一起来学习一下三子棋小游戏用C语言怎么写出来? 三子棋小游戏 1.游戏规则介绍2.游戏准备3.游戏的实现3.1生成菜单3.2游戏的具体实现3.2.1初始化棋盘3.2.2打印棋盘3.2…...

宝塔Linux面板点击SSL闪退打不开?怎么解决?
宝塔Linux面板点击SSL证书闪退如何解决?旧版本的宝塔Linux面板确实存在这种情况,如何解决?升级你的宝塔Linux面板即可。新手站长分享宝塔面板SSL闪退的解决方法: 宝塔面板点击SSL证书闪退解决方法 问题:宝塔Linux面板…...

Problem: 6953. 判断是否能拆分数组
Problem: 6953. 判断是否能拆分数组 文章目录 思路解题方法复杂度Code 思路 针对题目中的以下目标,可以转换寻求数组中是否存在前后两个元素之和>m的情况,如果存在则返回ture,如果不存在则返回false。能这样转换的原因是,如果…...

MobiSys 2023 | 多用户心跳监测的双重成形声学感知
注1:本文系“无线感知论文速递”系列之一,致力于简洁清晰完整地介绍、解读无线感知领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; MobiCom, Sigcom, MobiSys, NSDI, SenSys, Ubicomp; JSAC, 雷达学报 等)。本次介绍的论文是:<<MobiSys’23,Multi-User A…...

Netty:ChannelInitializer添加到ChannelPipeline完成任务以后会自动删除自己
说明 io.netty.channel.ChannelInitializer是一个特殊的ChannelInboundHandler。它的主要作用是向 Channel对应的ChannelPipeline中增加ChannelHandler。执行完ChannelInitializer的initChannel(C ch)函数以后,ChannelInitializer就会从ChannelPipeline自动删除自己…...

【VUE】项目本地开启https访问模式(vite4)
在实际开发中,有时候需要项目以https形式进行页面访问/调试,下面介绍下非vue-cli创建的vue项目如何开启https 环境 vue: ^3.2.47vite: ^4.1.4 根据官方文档:开发服务器选项 | Vite 官方中文文档 ps:首次操作,不要被类…...

【状态估计】一维粒子滤波研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

设计模式-迭代器模式在Java中使用示例
场景 为开发一套销售管理系统,在对该系统进行分析和设计时,发现经常需要对系统中的商品数据、客户数据等进行遍历, 为了复用这些遍历代码,开发人员设计了一个抽象的数据集合类AbstractObjectList,而将存储商品和客户…...

Maven入职学习
一、什么是Maven? 概念: Maven是一种框架。它可以用作依赖管理工具、构建工具。 它可以管理jar包的规模、jar包的来源、jar包之间的依赖关系。 它的用途就是管理规模庞大的jar包,脱离IDE环境执行构建操作。 具体使用: 工作机…...

【多音音频测试信号】具有指定采样率和样本数的多音信号,生成多音信号的相位降低波峰因数研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

LeetCode150道面试经典题-删除有序数组中的重复项(简单)
1.题目 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k ,…...

人大金仓数据库Docker部署
docker 搭建 yum -y install yum-utilsyum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.reposystemctl start docker.servicesystemctl enable docker.servicesystemctl status docker.service 配置Docker cd /etc/docker/ vi da…...

Leetcode-每日一题【剑指 Offer 07. 重建二叉树】
题目 输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,20,7]Output: [3,9,20,null,null,15,7] 示例 2: Input: preo…...

Shell编程快速入门
Shell编程快速入门 脚本格式要求 脚本以#!/bin/bash开头脚本需要有可执行权限 脚本的常用执行方式 方式1:输入脚本的绝对路径或相对路径方式2:sh脚本 Shell的变量 Shell变量介绍 Linux Shell中的变量分为系统变量和用户自定义变量 系统变量&#…...

wpf 3d 坐标系和基本三角形复习
wpf 3d 坐标系的描述见此, WPF 3d坐标系和基本三角形_wpf 坐标系_bcbobo21cn的博客-CSDN博客 X轴正向向右,Y轴正向向上;Z轴,正向是从屏幕里边出来,负向是往屏幕里边去;坐标原点是在呈现区域的中心&#x…...

如何安全变更亚马逊收款账户?
有太多的卖家想知道如何安全变更亚马逊收款账户,因为更改了第三方收款账户可能会导致二次视频认证或者增强视频。真的是这样吗? 其实不推荐亚马逊店铺正常运营之后去变更信用卡,收款账户等重要资料的,因为玩黑科技的卖家也真的多…...

大数据面试题:Hadoop中的几个进程和作用
面试题来源: 《大数据面试题 V4.0》 大数据面试题V3.0,523道题,679页,46w字 可回答:1)启动Hadoop,都会有什么进程 参考答案: 1)NameNode:Master…...

题解:ABC276D - Divide by 2 or 3
题解:ABC276D - Divide by 2 or 3 题目 链接:Atcoder。 链接:洛谷。 难度 算法难度:入门。 思维难度:入门。 调码难度:入门。 综合评价:极简。 算法 数论。 思路 由大脑可知&#x…...

后台管理系统
1.1 项目概述 简易后台管理系统是一个基于Vue3ElemrntPlus的后台管理系统,提供了用户登录、记住密码、数据的增删改查、分页、错误信息提示等功能,旨在协助管理员对特定数据进行管理和操作。 没有后台对接,数据源为假数据。 全部代码已上传G…...

C++数据结构之平衡二叉搜索树(一)——AVL的实现(zig与zag/左右双旋/3+4重构)
本文目录 00.BBST——平衡二叉搜索树01.AVL树02.AVL的插入2.1单旋——zig 与 zag2.2插入节点后的单旋实例2.3手玩小样例2.4双旋实例2.5小结 03.AVL的删除3.1单旋删除3.2双旋删除3.3小结 04.34重构05.综合评价AVL5.1优点5.2缺点 06.代码注意插入算法删除算法完整代码:…...

静态库和动态库
库文件 库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。 库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。库文件有两种&a…...

用于Voronoi图构建的Fortune算法的C++实现
Voronoi图是一种在计算几何中广泛使用的数据结构,它可以用于解决最近邻搜索、路径规划等问题。在这篇文章中,我们将探讨一种用于构建Voronoi图的高效算法——Fortune算法,并提供其C实现。 一、Voronoi图简介 Voronoi图是由一组点在平面上生…...

笔记汇总 | 斯坦福 CS229 机器学习
文章目录 前言课程参考文章推荐阅读 前言 本文为斯坦福大学 CS229 机器学习课程学习笔记 本文主体部分转载自黄海广博士,文末已给出链接,大家有兴趣可以直接访问笔记首页,下载对应课程资料及作业代码 课程官网:CS229: Machine …...

git 版本管理工具 学习笔记
git 学习笔记 目录 一、git是什么 二、创建仓库 三、工作区域和文件状态 四、添加和提交文件 五、回退版本 (了解) 六、查看差异 七、删除文件 八、.gitignore文件(了解) 九、github ssh-key配置 十、本地仓库和远程仓库内…...

Bean基本注解开发和Bean依赖注入注解开发
目录 1.Bean基本注解开发 Component Scorelazy PostConstruct和PreDestroy RepositoryServiceController 2.Bean依赖注入注解开发 Value Autowired Qualifier Resource 扩展AutoWired 1.Bean基本注解开发 基本Bean注解,主要是使用注释的方式替代原有xml的…...