Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

到達不能コード

コードが実行中に到達できません。

説明

このチェックでは、コード セクションが静的に到達不能であるかどうかが判別されます。到達可能性を判別するために、コード セクションが実行されるかどうかを判定する条件を評価します。

  • 少なくとも 1 つの条件が静的に true と評価された場合、そのコード セクションは到達可能とみなされます。

  • すべての条件が常に false に評価される場合、そのコード セクションは到達不能コードとして表示されます。

  • まったく評価されない条件、または常に true に評価される条件も、到達不能コードとして表示されます。

到達不能コードの例には以下があります。

  • if 条件式が常に false に評価される場合、対応するコード分岐には到達できません。[ソース] ペインで、分岐の左中かっこはグレーになります。

  • if 条件式が常に true に評価される場合、この条件は冗長です。[ソース] ペインで if キーワードがグレー表示されます。

  • コードの前に break または return ステートメントがある。

[ソース] ペインでコード ブロックの左中かっこがグレーで表示される場合、ブロック全体を強調表示するには、中かっこをダブルクリックします。

チェックは関数内のコードで動作します。[呼び出されていない関数] および[到達不能な関数] のチェックにより、関数自体が呼び出されていないか、もしくは到達不能コードから呼び出されているかが判定されます。

すべて展開する

#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));
    }
  }
} 

この例では、mainif(checkInit(myState)) の分岐に入るのは myState = Init の場合のみです。したがって、分岐内で Polyspace®myState には値 Init が含まれるとみなします。checkWait(myState) は常に False を返し、if(checkWait(myState)) の第 1 の分岐は到達不能です。

修正 — 冗長なテストを削除

1 つの修正方法として、冗長なテスト 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 キーワード上に表示されて、冗長状況を示します。

修正 — 冗長なテストを削除

1 つの修正方法として、条件 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 テストの 2 つの部分は || で結合されているため、if テストは、2 番目の部分に関わりなく常に true になります。したがって、if テストの 2 番目の部分は到達不能です。

修正 — テストを && で結合

1 つの修正方法として、|| ではなく && によって if テストの 2 つの部分を結合するとします。

#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() の 2 つの呼び出しを調べてみます。f() の最初の呼び出しでは、switch ステートメントで case init が選択されます。case init 内では、b は全範囲を取ることができます。b が 3 に等しい場合、a は completion に設定されます。関数 f() の 2 回目の呼び出しでは、switch ステートメントでは case init または case 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() では、次の行の break ステートメントが実行されないため、チェックでは case 3 のデッド コードが示されます。

チェック情報

グループ: データ フロー
言語: C | C++
頭字語: UNR

バージョン履歴

すべて展開する