我是靠谱客的博主 开心镜子,这篇文章主要介绍圈复杂度Cyclomatic complexity一、什么是圈复杂度二、如何计算圈复杂度三、圈复杂度阈值四、如何降低圈复杂度,现在分享给大家,希望可以做个参考。

一、什么是圈复杂度

        圈复杂度(Cyclomatic complexity,简写 CC)也称为条件复杂度,是模块结构复杂度的度量,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数。

        成立于1976年的McCabe&Associates公司开发出了McCabe Cyclomatic Complexity Metric(圈复杂度)技术。Metric以软件复杂度测量的数目为基础,能帮助工程师识别难于测试和维护的模块,圈复杂度已经成为评估软件质量的一个重要标准。人们可以用圈复杂度对软件的复杂度和质量进行衡量,来安排工程进度,在成本、进度和性能之间寻求平衡。

        研究表明,程序的Cyclomatic复杂性与其可维护性和可测试性之间存在相关性,这意味着对于更高复杂性的文件,在修复、增强或重构源代码时出错的概率更高。但是要注意,McCabe度量数大的程序,不见得结构化就不好。例如,Case语句是良结构的,但可能有很大的McCabe度量数(依赖于语句中的分支数),这可能是由于问题和解决方案所固有的复杂性所决定的。使用者应当自己决定如何使用McCabe度量所提供的信息。

二、如何计算圈复杂度

圈复杂度Cyclomatic complexity =(1 + ifs + loop + case),其中

ifs     - number of if, else if,else statements in the current function

loop  - number of for, while, and do-while statements in the current function

case - the number of switch branches in the function (without default)

要注意的是,人工计算cc时要包含宏展开之后的代码中的if、case等语句。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void FDL_AnalyEraseCmd(void) { U08 bNode, PtStat; bNode = gtFdlDrvSubmQ.tCmdClassLink.tLinkArg[FDL_CMD_CLASS_ERASE].bHead; while (bNode != INVALID_U8) //有效节点,则说明有有效命令需要处理 { if (FALSE == gtFdlDrvSubmQ.bCfg2FcFlg[bNode]) { YS_ASSERT((FDL_DRV_SEG_HEAD_TAIL == gtFdlDrvSubmQ.sDrvCmd[bNode].bSegFlg), "FDL_AnalyEraseCmd-->err1"); YS_ASSERT((FDL_DRV_CMD_ERASE == gtFdlDrvSubmQ.sDrvCmd[bNode].bCmd), "FDL_AnalyEraseCmd-->err2"); PtStat = Thread_FDL_EraseCmd(&PT_PrcsErsCmd[0], bNode); if (PT_ENDED != PtStat) { break; } } bNode = gtFdlDrvSubmQ.tCmdClassLink.bLinkNext[bNode]; } }

上述代码的圈复杂度为 1+2+1+0=4。

拓展概念:

Extended cyclomatic complexity:在圈复杂度的计数基础上加上逻辑布尔运算符。每当Klocwork在条件语句中找到逻辑布尔运算符(&&或|)时,EXTCYCLOMATIC就会增加1。

Plain cyclomatic complexity:类似于圈复杂度,但是在预处理器扩展之前计算,从宏定义生成的任何条件语句都不会生成PLAINCYCLOMATIC度量。

Plain extended cyclomatic complexity :类似于扩展圈复杂度,但在预处理器扩展之前计算,从宏定义生成的任何条件语句都不会生成此度量。

三、圈复杂度阈值

Cyclomatic Complexity

Risk Evaluation

1-10

一个没有太大风险的简单模块

11-20

具有中等风险的更复杂模块

21-50

高风险的复杂模块

51 and greater

风险极高的不稳定项目

四、如何降低圈复杂度

        分两个方向降低圈复杂度,一是拆分函数,二是尽量减少if、else、while、case等这些流程控制语句。

4.1 拆分函数

        圈复杂度的计算范围是在一个function内的,将业务代码拆分成一个一个的职责单一的小函数,如此除了能够降低圈复杂度,也能提高代码的可读性和可维护性。

4.2 减少流程控制

1. 减少不必要条件、循环分支,尽量少用 if …else … ,采用三元表达式替换 if else;

复制代码
1
2
3
4
5
6
7
8
9
10
11
if (DMAINFO_ABNORMAL(wDmaSts)) { bRetryType = RD_ERR_DATA_ERROR; /*软解Fail*/ } else { bRetryType = RD_ERR_SOFT_PASS; /*软解Pass*/ } //修改后: bRetryType = (DMAINFO_ABNORMAL(wDmaSts)) ? RD_ERR_DATA_ERROR : RD_ERR_SOFT_PASS;

2. 合并条件表达式,比如使用 a || b || c;

3. 去掉没有必要的else

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (false) { return; } else { c = a; } //修改后: if (false) { return; } c = a;

4. 同一条件多处出现,重构函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
if (b) { if (a) { Func1(); } } else { if (a) { Func2(); } } if (a) { Func3(); } //修改后: if (a) { if (b) { Func1(); } else { Func2(); } Func3(); }

5. 未完待续;

注:以上圈复杂度计算与复杂度分级均基于klocwork平台的metric。

最后

以上就是开心镜子最近收集整理的关于圈复杂度Cyclomatic complexity一、什么是圈复杂度二、如何计算圈复杂度三、圈复杂度阈值四、如何降低圈复杂度的全部内容,更多相关圈复杂度Cyclomatic内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(106)

评论列表共有 0 条评论

立即
投稿
返回
顶部