MSC21-C. ループの終了条件には不等式を用いる
while 文や for 文でループカウンタを使用する場合、等価演算子 != を用いてループを終了させるよりも、< などの関係演算子を用いる方が安全である。
違反コード (等価演算子 !=)
以下のコード例では反復処理を5回行うように見えるが、実際にはループは終了しない。
for ( i = 1; i != 10; i += 2 ) { // ... }
適合コード (関係演算子)
関係演算子 <= を用いており、ループは確実に終了する。
for ( i = 1; i <= 10; i += 2 ) { // ... }
違反コード (等価演算子)
また、ループインデックスの初期値と終了値が変数で与えられるようなループでは、確実に終了することを確認することが重要になる。以下の関数は、begin < end が真であると仮定しており、そうでない場合には無限ループになる。
void f(int begin, int end) { int i; for (i = begin; i != end; ++i) { /* ... */ } }
適合コード (関係演算子)
繰り返しになるが、等価演算子ではなく関係演算子を用いることでループが終了することを保証できる。begin >= endが真の場合、ループの本体は実行されない。
void f(int begin, int end) { int i; for (i = begin; i < end; ++i) { /* ... */ } }
違反コード (境界条件)
数値比較演算子は、INT_MIN や INT_MAX などある型で表現できる最大もしくは最小値と比較すると、必ずしもループを終了しないことがある。
void f(int begin, int step) { int i; for (i = begin; i <= INT_MAX; i += step) { /* ... */ } }
適合コード (境界条件)
以下の適合コードでは、ある型の最大値とインクリメントする値との差分と、ループカウンタとを比較している。
void f(int begin, int step) { if (0 < step) { int i; for (i = begin; i <= INT_MAX - step; i += step) { /* ... */ } } }
例外
MSC21-EX1: ループカウンタが1であり、ループの開始値が終了値より小さいもしくは等しいことが事前に分かっているなら、ループの終了に等価演算子を用いてもよい。同様に、ループカウンタが-1であり、ループの開始値が終了値よりも大きいもしくは等しいなら、等価演算子を用いてループを終了してもよい。
int i; for (i = 1; i == 5; ++i) { /* ... */ }
リスク評価
等価演算子による判定は、ループの終了に予想以上に時間がかかったり、ループがまったく終了しないというリスクを伴う。
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MSC21-C | 低 | 低 | 低 | P1 | L3 |
自動検出
ROSE はこのレコメンデーションの違反を検出できる。
参考情報
- [MISRA 04]
翻訳元
これは以下のページを翻訳したものです。
MSC21-C. Use inequality to terminate a loop whose counter changes by more than one