历史上的今天
返回首页

历史上的今天

今天是:2025年08月05日(星期二)

正在发生

2021年08月05日 | MC9S12G128模块化分层化软件架构之八_QAC静态代码分析

2021-08-05 来源:eefocus

1 overview

1.1 目的

本文档用于起点开发板的软件优化说明。


不局限于硬件功能的实现,着眼于实现高质量、优美的软件。                           

2 QAC基础知识

2.1 introduction

QA·C是用于C代码的深度静态分析器。 QA·C旨在帮助提高软件开发的质量。


QA·C在逐个文件和完整项目的基础上分析源代码,以识别C语言的危险用法。包含1300多个警告消息的库用于突出显示那些不可移植的、难以维护的、过于复杂或可能引起问题的方式编写的源码。


该工具还可以识别不符合ISO C90标准(ISO / IEC 9899:1990)或依赖于未指定、未定义的行为的语言用法。该工具会在使用ISO C99标准的特定功能时发出警告,但确实支持其中许多功能的语义。


整个项目的源代码的警告消息通过浏览器显示,该浏览器对所有源文件中出现的消息进行分类和分组。


该工具的其他功能包括:


•提供可量化衡量代码属性的代码度量:基于函数的33个,基于文件的30个和项目级别的4个;


•功能结构图,可深入了解控制流程;


•关系图,用于演示函数调用,全局引用和文件树;


•关系统计分析,根据行业基准对代码质量进行全面评估;


•跨模块分析(CMA)功能,分析功能递归和各种全局标识符问题;


•一个基准模块,可简化对遗留代码的修改。


2.2 message等级

QAC中将message分为10个等级。


2.2.1 Level0:information

information等级的警告重要性最低。

image.png?imageView2/2/w/550

2.2.2 Level 1: Obsolete Messages

保留标记为过时的消息是为了向后兼容2个产品版本,并将随后将其删除。


2.2.3 Level 2: Minor

级别2信息识别那些可能会违反编码标准要求的问题,但这些问题不一定是严重的错误。级别2信息组与C语言的不同方面相关联。


2.2.4 Level 3: Major

Major信息是那些可能会识别出重大编码错误,异常或问题的信息。通常认为这些信息(如7、8和9级)太重要了,以至于没有充分的理由就无法忽略。 3级信息组与C语言的不同方面相关联。


2.2.5 Level 4: Local Standards

级别4信息识别那些不符合您的编程标准的功能。按照惯例,在安装QA·C模块时,会将其他信息组添加到级别4,其中将包含与编码标准中特定规则相对应的信息。


2.2.6 Level5: Dataflow Analysis

此级别的信息对运行时行为进行分析,确定问题,从严重的问题(如未定义的行为)到经常与编码和逻辑错误相关的条件。

image.png?imageView2/2/w/550

overflow and wraparound:


当整数值增加到太大而无法存储在关联表示中时,就会发生整数溢出或环绕。发生这种情况时,该值可能会变成非常小的值或负数。当结果用于控制循环,做出安全性决定或确定行为的偏移量或大小(例如内存分配,复制,串联等)时,这对安全性至关重要。


2.2.7 Level 6: portability

image.png?imageView2/2/w/550

2.2.8 Level 7: Undefined behavior

image.png?imageView2/2/w/550

3 meesage help

image.png?imageView2/2/w/550

4 QAC 报issue的点

4.1  LEVEL6: [C99]Trailing comma at the end of an enumerator-list.

枚举列表末尾的逗号。


ISO C99language features.


在枚举常量列表的末尾有逗号。ISO:C90无法识别此语法,但是ISO:C99允许使用此语法。


forexample:


 enum ED { ZERO=0, TWO=2, FOUR=4, };


对应的MISARC 2004 rule:1.1。


4.1.1 修改的代码

4.1.1.1 drio.h

等。

4.1.1.2 mdio_cfg.h

等。


4.2  level 7: The identifier is reserved for use by the library.

标识符保留给库使用。


使用保留名称去定义一个标识符不可取,因为该名称可能与系统库的现有版本或将来版本中的标识符冲突。以下标识符保留:


a)以2个下划线开头;


b)以1个下划线紧跟着一个大写字母开头;


c) 以1个下划线和一个其他的标识符开头;


4.2.1  例子

int __glob = 0;  /* 不符合 */


int _Glob = 1;   /* 不符合 */


对应的MISAR C 2004 rule:20.2。


4.2.2 修改的代码

4.2.2.1  apl_key.h

等。


4.3 level 3: An expression of ‘essentially signed’ type is being used asthe operand of this bitwise operator.

原始有符号类型的表达式用作位运算的操作数。


4.3.1  例子

void foo(int a)


{

a & 1u;           /* 不符合 */


a | 1u;            /* 不符合 */


~a;                 /* 不符合 */


a >> 1u;         /* 不符合 */


1u << a;         /* 不符合 */


}


对应的MISARrule 12.7。


4.3.2 对应代码中的message

4.3.2.1 drint.c

4.3.3 修改的代码

4.3.3.1 drint.c

4.4 level3: An expression of ‘essentially Boolean’ type is being converted tounsigned type on assignment.

分配时,“基本布尔”类型的表达式将转换为无符号类型。


相关的MISARCrule 10.1。


例子:


void foo (unsigned b);


unsigned test (int a)


{

unsigned uia = (a != 0);  /*不符合*/


foo(a < 0);                      /*不符合*/


uia = (a < 0);                 /*不符合*/


return (a == 0);              /*不符合*/


}


对应的MISAR C 2004rule 10.1。


4.4.1 修改的代码

4.4.1.1 bitop.h

BYTEOP_BIT_READ原宏定义:


#defineBYTEOP_BIT_READ_AT(data, bitidx)             (((uint8)(data) & BYTEOP_POWER_2(bitidx)) != 0U)


返回的值为bool型,true or false


改为:


#defineBYTEOP_BIT_READ_AT(data, bitidx)             ((((uint8)(data) & BYTEOP_POWER_2(bitidx)) != 0U) ? (uint8)1U :(uint8)0U)


返回的值为1U或0U

4.5  level 2: Loop control variable in this ‘for’ statement is modifiedin the body of the loop.

for语句的循环控制变量在循环体中被修改了。


在此“ for”循环中,被识别为控制变量的变量在循环体内进行了修改。


QAC通过检查 “ for-loop”中的3个表达式的来识别控制变量。通常,它是第二个表达式中的变量,并且是关系运算符的操作数。


在常规的for循环中,仅在for语句的第三个表达式中修改循环控制变量。循环中其他位置的修改可能会引起混乱。


4.5.1 例子

extern void foo(void)


{

int j;


for (j = 0; j < 10; j++)


{

   ++j;


}


}


对应的MISARC2004rule: 13.6。


4.5.2  对应的代码中的message

4.5.3 修改的代码

4.5.3.1 drint.c

4.6 level 2: This statement has no side-effect – it can be removed.

语句没有side-effect,可以移除。


可以被优化掉的代码。


sideeffects: 更改执行环境的动作。访问易失性对象,修改对象,修改文件或调用执行任何这些操作的函数都是副作用。


4.6.1 例子

void foo( int x )


{

int n = 0;


n == x;           /*报警告*/


}


对应的MISAR2004Rule 14.2。


4.6.2 对应的代码中的message

4.6.3 修改的代码

4.6.3.1 mdio.c

等。


4.7 level 2: function with internal linkage, is being defined without aprevious declaration.

一个被内部引用的函数在定义时没有提前的声明。


在文件中定义的所有的函数都应在文件顶部加原型声明,这很有帮助。这样可以避免在函数被声明之前被调用的可能性。在文件开始处的一个位置记录函数接口的方式也很有用。


例子:


static voidfoo(void)        /*没有提前声明*/


{

}


对应的MISAR 2004rule 8.1


4.7.1 对应的代码中的message

4.7.1.1 mdio.c

4.7.2  修改的代码

4.7.2.1 mdio.c


在文件头部增加static uint8 mdio_find_in_input_cfg(uint8port, uint8 pin)函数声明。


4.8 level 2:A function counld probably be used instead of this function-like macro.

类似函数的宏应当用函数替换。


该宏是表达式的形式,因此可以用一个函数代替。用函数替换类似函数的宏并不总是可行或方便。但是函数通常比宏更安全,因为可以对参数执行类型检查。


下面这些类似函数的宏会导致该条信息的产生:


·  有至少一个参数;


·  不包含’#’ or ‘##’操作符;


·  不包含’ {}; ‘或任何关键字;


对应的MISARC2004rule: 19.7。


4.8.1 例子

#define M1(a, b, c)    ( (a) + (b) + (c))        /* 不符合 */


#define M6(A, B)       ((A)[1] +(B)[2])         /* 不符合 */


对应的MISAR C2004 rule 19.7。


需要写成do-while(0)格式。


为什么写成do-while(0)格式,请看MISARC2004rule: 19.4 和 19.10。


4.9 level 8:initializer pointer to a more heavily qualified type.

初始化程序指向更严格的类型。


指针已使用表达式进行了初始化,该表达式指向更严格的类型。


ISO: C要求被初始化对象的类型必须具有初始化者指向的类型的所有的qualifier。因此,不允许使用类型为“ const TYPE *”(指向const TYPE的指针)或“ volatile TYPE *”(指向volatile TYPE的指针)的表达式来初始化类型“ TYPE *”(指向TYPE的指针)的对象;这样做将违反类型资格限制。


另一方面,使用类型“ TYPE *”的表达式初始化“ const TYPE *”或“ volatile TYPE *”甚至“ const volatile TYPE *”类型的对象是完全合法的。


原文:


A pointer has been initialized with anexpression which points to a more heavily qualified type.


ISO:Crequires that the type pointed to by the initialised object must have all thequalifiers of the type pointed to by the initializer. It is therefore notpermissible to initialize an object of type "TYPE *" (pointer toTYPE) with an expression of type "const TYPE *" (pointer to constTYPE) or "volatile TYPE *" (pointer to volatile TYPE); to do so wouldpermit type qualification restrictions to be violated.


On theother hand, it is perfectly legitimate to initialize an object of type"const TYPE *" or "volatile TYPE *" or even "constvolatile TYPE *" with an expression of type "TYPE *".


4.9.1 例子

extern int                        *gpi;


extern const int             *gpci;


extern volatile int          *gpvi;


extern const volatile int * gpcvi;


void test (void)


{

int                       *xpia    = gpi;            /* no message */


int                       *xpb     = gpci;          /* 不符合 */


int                       *xpc     = gpvi;          /* 不符合 */


int                       *xpd     = gpcvi;        /* 不符合 */


 


const int              *xpcia  = gpi;           /* no message */


const int              *xpcib  = gpci;         /* no message */


constint              *xpcic  = gpvi;         /* 不符合 */


constint              *xpcid  = gpcvi;      /* 不符合 */


 


volatile int           *xpvia  = gpi;           /* no message */


volatile int           *xpvib  = gpci;         /* 不符合 */


volatile int           *xpvic  = gpvi;         /* no message */


volatile int           *xpvod = gpcvi;      /* 不符合 */


 


const volatile int *xpcvia = gpi;          /* no message */


const volatile int *xpcvib = gpci;        /* no message */


const volatile int *xpcvic = gpvi;        /* no message */


const volatile int *xpcvid = gpcvi;      /* no message */


}


4.9.2 对应的代码中的message

4.9.2.1 drio_cfg.c

4.9.3 修改的代码

4.9.3.1 drio_cfg.h


typedef uint8 * DrRegType;


改为


typedef uint8 * DrRegType;

因为DDRE的定义和使用为:

4.10 level 3: A non-constantexpression of ‘essentially signed’ type is being converted to unsigned type onassignment.

“原始有符号的”类型的非常量的表达式转换为无符号类型。


void foo(unsigned b);


unsignedtest(short a)


{   


unsigned  uia = a;           /* 不符合 */


foo( a + 1 );                     /* 不符合 */


uia = (a – 1);                   /* 不符合 */


return a;                          /* 不符合 */


}


4.10.1 对应的代码中的message

4.10.2 修改的代码

4.10.2.1 drio.c

4.11 level2: Array declared with unknown size.

大小未知的数组声明。


数组声明时类型不完整。


仅当数组具有外部连接时才允许这样做。一些编码标准不赞成这种做法,因为它阻止工具检查数组下标操作的有效性。


4.11.1 例子

extern int xa[10];


extern int xb[];                       /* 警告 */


extern void foo(void)


{

xa[10] = 0;                        /* 警告,越界 */


xb[10] = 0;                        /* 没有警告,数组大小未知 */


}


对应的MISAR C2004 rule: 8.12。


4.11.2 修改的代码

4.11.2.1 drio_cfg.h

4.12 Macroparameter not enclosed in ().

宏参数未包含在()中。


在某些宏中,将参数括在替换列表的括号中这一操作很重要。并非所有的宏或所有参数都是如此。这取决于宏中如何使用参数。在某些类型的表达式中,将宏参数用作操作数时就会出现问题。考虑以下示例:


#define SQUARE(A)   (A * A)             /* 报警告 */

推荐阅读

史海拾趣

Efficient Power Conversion公司的发展小趣事

作为一家技术驱动的公司,EPC公司一直致力于持续创新和产品研发。近年来,公司不断推出新的氮化镓功率半导体器件和集成电路产品,以满足市场不断变化的需求。其中,EPC公司全新推出的ePower功率级集成电路系列,为高功率密度应用提供了更高性能及更小型化的解决方案。这一系列产品在市场上获得了良好的反响,进一步巩固了EPC公司在氮化镓技术领域的领先地位。

Avic公司的发展小趣事

随着Avic公司在航空电子技术领域的不断发展和创新,其产品在国内外市场上的竞争力日益增强。公司成功拓展了国内外市场,市场份额稳步增长。这不仅体现了公司在航空电子领域的实力,也为中国航空工业的整体发展做出了积极贡献。

这五个故事虽然不能完全涵盖Avic公司在电子行业发展的所有细节,但希望能通过概括性的描述,为您展现该公司在这一领域的重要发展历程和取得的成就。需要注意的是,这些故事是基于公开资料和已知事实进行描述的,旨在客观呈现事实,而非进行主观评价。

Abilis Systems公司的发展小趣事

随着全球化的推进,Avic公司不断加强与国际航空工业界的合作。公司与多家国际知名航空企业建立了战略合作关系,共同开展航空电子技术的研发和生产。这些合作不仅促进了中国航空工业与国际先进水平的接轨,也为中国航空工业的国际化发展提供了有力支持。

AOS公司的发展小趣事

随着技术的不断发展和市场的扩大,AOS公司开始积极寻求全球扩张的机会。1998年,AOS在南京独资成立了中国总部,开始了其在中国的深耕之旅。通过多年的努力,AOS在中国建立了完善的产研基地和销售网络,其产品横跨家用和商用两大领域,赢得了广大消费者的信任和喜爱。如今,AOS已成为中国市场上备受推崇的热水设备品牌之一。

APLUS Products公司的发展小趣事

随着国内市场的不断饱和,APLUS Products公司开始寻求国际化发展的道路。在XXXX年,公司成功打入欧洲市场,并在当地建立了分支机构。通过深入了解欧洲消费者的需求和偏好,公司不断优化产品设计和营销策略,逐渐赢得了欧洲消费者的认可和喜爱。

Electro-Optical Systems Inc公司的发展小趣事

EOS公司成立于1983年,创始人是一群热衷于红外技术的专家。他们深知红外探测器在军事、科研和工业领域的重要性,于是决定投身于这一领域。初创时期,EOS面临着资金短缺、技术难度大等挑战,但团队成员凭借着对技术的执着和对市场的敏锐洞察,逐步攻克难关,成功研制出第一批红外探测器产品。

问答坊 | AI 解惑

求助:这个元件是什么?

这是SD卡读卡器原理图的一部分,谁能告诉我,其中标注出的L1,L2,L3,L5是什么元件。封装是什么样的。谢谢了!…

查看全部问答>

嵌入式学习平台

华禹提供手机主控解决方案P1300,手机行业第一家进军嵌入式 完全替换GPRS模块,不需要用AT命令,直接调用socket函数即可。模块自身104MHz的ARM7 CPU主控外设,并且外部有显示,音频等等,开发采用C语言和JAVA,特别适合企业客户,降低成本,缩短开 ...…

查看全部问答>

求问 什么是MO/MT call 啊?

看到网上都说的不仔细 到底是什么东西 一个是打入 一个是接听么? 还是什么东西啊…

查看全部问答>

移植要从何处下手

给一块板子,一个设备(已有驱动),要移植,主要从哪些方面下手呢,对具体的设备原理要先掌握吗?…

查看全部问答>

请教s3c2442的sdram初始化问题

各位朋友,请问有做过s3c2442的么?我现在在调试s3c2442的开发板,uart和nand flash已经测试可用了,但是到sdram的时候卡住了 具体的问题就是:根据s3c2442的数据手册,初始化之前首先要precharge all,我看了precharge all的真值表,需要设置RA ...…

查看全部问答>

谁能给提供一个模拟调光的电路啊?

谁能给提供一个模拟调光的电路啊?dc12V输入 负载是4个led串联 想通过模拟的方式让led逐渐点亮逐渐熄灭 谁能帮忙提供一下这个电路啊 谢谢…

查看全部问答>

询问WinCE开发环境

  WinCE超级rookie,询问在ARM9上开发WinCE应用程序需要搭配什么IDE环境。   感谢达人帮助。…

查看全部问答>

家用手提灯和应急灯

本文介绍的这款由法国设计师Arnaud Lapierre设计的手提灯,设计非常简洁,由于电线的牵绊,仅适合家用。另外其结构也十分简单,完全可以自己动手做一个。 …

查看全部问答>

板子覆铜是否会增加板子总体功耗

对双面板而言,双面覆铜或者单面覆铜,在对功耗敏感的场合中,覆铜是否会增加板子自身的总体功耗呢? …

查看全部问答>

请教有源低通滤波器和直流电压跟随问题

1、以上有源低通滤波直流跟随电路,用TINA仿真V_IN和V_OUT可以跟随的很好,电压差几十uV左右,实际电路中V_IN在0.5V时V_OUT会高出13mV左右,V_IN在4.5V时V_OUT会高出2mV左右,测试电路中V_IN电压变化由R2、R5分压产生,请问是什么原因如何解决跟 ...…

查看全部问答>