我是靠谱客的博主 开心镜子,最近开发中收集的这篇文章主要介绍圈复杂度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等语句。

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;

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

if (false) 
{     
	return; 
}
else
{     
	c = a;
}

//修改后:
if (false) 
{     
	return; 
}
c = a;

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

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 complexity一、什么是圈复杂度二、如何计算圈复杂度三、圈复杂度阈值四、如何降低圈复杂度所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部