Main Content

不可达代码

在执行期间无法到达的代码

描述

此检查用于确定一段代码是否静态不可达。为了确定可达性,此检查会评估决定是否执行一段代码的条件。

  • 如果至少有一个条件的静态评估结果为 true,则认为该段代码可达。

  • 如果所有条件的评估结果始终为 false,则该段代码将显示为不可达代码。

  • 根本不评估或评估结果始终为 true 的条件也显示为不可达代码。

不可达代码的示例包括下列项:

  • 如果 if 条件表达式的评估结果始终为 false,则无法到达相应的代码分支。在窗格中,该分支的左大括号显示为灰色。

  • 如果 if 条件表达式的评估结果始终为 true,则该条件是冗余的。在窗格中,if 关键字显示为灰色。

  • 跟在 breakreturn 语句后的代码。

如果某个代码块的左大括号在窗格中显示为灰色,要突出显示整个块,请双击该大括号。

检查操作的对象是函数内的代码。未调用函数不可达函数检查将确定是否函数本身未被调用,或者是从不可达代码内调用的。

对此检查进行诊断

Review and Fix Unreachable Code Checks

示例

全部展开

#define True 1
#define False 0
 
typedef enum {
  Intermediate, End, Wait, Init
} enumState;
 
enumState input();
enumState inputRef();
void operation(enumState, int);
  
int checkInit (enumState stateval)  {
  if (stateval == Init) 
    return True;
  return False;
}
 
int checkWait (enumState stateval)  {
  if (stateval == Wait) 
    return True;
  return False;
}
  
void main()  {
  enumState myState = input(),refState = inputRef() ;
  if(checkInit(myState)){
    if(checkWait(myState)) {
      operation(myState,checkInit(refState));	
    } else {
      operation(myState,checkWait(refState));
    }
  }
} 

在此示例中,只有当 myState = Init 时,main 才会进入 if(checkInit(myState)) 分支。因此,在该分支内,Polyspace® 会认为 myState 具有值 InitcheckWait(myState) 始终返回 False 并且 if(checkWait(myState)) 的第一个分支是不可达的。

更正 - 删除冗余测试

一种可能的更正方法是删除冗余测试 if(checkWait(myState))

#define True 1
#define False 0
 
typedef enum {
  Intermediate, End, Wait, Init
} enumState;
 
enumState input();
enumState inputRef();
void operation(enumState, int);

int checkInit (enumState stateval)  {
  if (stateval == Init) 
    return True;
  return False;
}
 
int checkWait (enumState stateval)  {
  if (stateval == Wait) return True;
  return False;
}
   
void main()  {
  enumState myState = input(),refState = inputRef() ;
  if(checkInit(myState))
    operation(myState,checkWait(refState));
} 
#include <stdlib.h>
#include <time.h>

int roll() {
  return(rand()%6+1);
}

void operation(int);
     
void main()   {
    srand(time(NULL));
    int die = roll();
    if(die >= 1 && die <= 6)
      /*Unreachable code*/
      operation(die);
  }

在此示例中,roll() 返回一个介于 1 到 6 之间的值。因此,main 中的 if 测试的计算结果始终为 true,是冗余的。如果有一个对应的 else 分支,则 else 语句上会显示灰色错误。如果没有 else 分支,则 if 关键字上会显示灰色错误来指示冗余情况。

更正 - 删除冗余测试

一种可能的更正方法是删除 if(die >= 1 && die <=6) 条件。

#include <stdlib.h>
#include <time.h>

int roll() {
  return(rand()%6+1);
}

void operation(int);
     
void main()   {
  srand(time(NULL));
  int die = roll();
  operation(die);
}
#include <stdlib.h>
#include <time.h>
#define True 1
#define False 0

int roll1() {
  return(rand()%6+1);
}

int roll2();
void operation(int,int);
    
void main()   {
  srand(time(NULL));
  int die1 = roll1(),die2=roll2();
  if((die1>=1 && die1<=6) || 
     (die2>=1 && die2 <=6))
  /*Unreachable code*/
    operation(die1,die2);
}

在此示例中,roll1() 返回一个介于 1 到 6 之间的值。因此,if 测试的第一部分 if((die1>=1) && (die1<=6)) 始终为 true。因为 if 测试的两个部分通过 || 组合在一起,所以不管第二部分如何,if 测试始终为 true。因此,if 测试的第二部分不可达。

更正 - 使用 && 来组合测试

一种可能的更正方法是使用 && 来组合 if 测试的两个部分,而非使用 ||

#include <stdlib.h>
#include <time.h>
#define True 1
#define False 0

int roll1() {
  return(rand()%6+1);
}

int roll2();
void operation(int,int);
    
void main()   {
  srand(time(NULL));
  int die1 = roll1(),die2=roll2();
  if((die1>=1 && die1<=6) && 
     (die2>=1 && die2<=6))
    operation(die1,die2);	
}
typedef enum {init, run, completion} states;

int getAnInput();

states a = init;

void f(int b)
{
    switch (a) {
    case init: {
        if (b == 3) {
            a = completion;
        }
        break;
    }
    case completion: {
        if (b == 1) {      //Unreachable code
            //....
        }
        break;
    }
        //...
    }
}

void main()
{
    int b = getAnInput();
    f(b);
    f(b);
}

有时候,某个代码块可能因为变量值受代码中前面的运算约束而不可达。如果您不理解为什么某个条件始终为 true 或 false,请查看条件中的变量是否因为前面的某个运算而受到约束。

在此示例中,函数 getAnInput() 已上桩,因为未提供它的定义。通过 getAnInput() 初始化的变量 b 可以接受 int 数据类型允许的任何值。在 f() 调用中,b 看起来可以具有包括值 1 和 3 在内的任何值。不过,条件 (b == 1) 似乎为 false,对应的代码块不可达。

请观察两个 f() 调用。在第一个 f() 调用中,switch 语句选择 case init。在 case init 中,b 可以是完整范围。如果 b 等于 3,则 a 被设置为 completion。第二次调用 f() 函数时,switch 语句可以选择 case initcase completion。因为可以选择 case completion 的唯一途径是当 b 先前等于 3 时,并且因为在 case init 外部没有对 b 进行操作,因此 Polyspace 假定 b 仍然等于 3。因此,if 语句条件 (b == 1) 永远不会得到满足,这导致 case completion 中出现不可达代码。

void test1 (int a)
{
    int tmp = 0;
    if ((a!=3))
        {
            switch (a)
                {
                case 1:
                    tmp++;
                    break;
                default:
                    tmp = 1;
                    break;
                /* case 3 falls through to
                   case 2, no dead code */
                case 3:
                case 2:
                    tmp = 100;
                    break;
                }
        }
}

void test2 (int a)
{
    int tmp = 0;
    if ((a!=3))
        {
            switch (a)
                {
                case 1:
                    tmp++;
                    break;
                default:
                    tmp = 1;
                    break;
// Dead code on case 3
                case 3:
                    break;
                case 2:
                    tmp = 100;
                    break;
                }
        }
}

在此示例中,switch 语句的 case 3 在函数 test1()test2() 中不可达。

  • test1() 中,case 3 将穿透执行到 case 2,并且检查结果显示没有死代码。

  • test2() 中,检查结果显示 case 3 存在死代码,因为下一行中的 break 语句未执行。

检查信息

组:数据流
语言:C | C++
缩写: UNR

版本历史记录

全部展开