【C言語】
Redundant condition
~冗長な条件~

(style) Redundant condition: If ‘x > 11’, the comparison ‘x > 10’ is always true.

冗長な条件。x > 11’の場合、比較の’x > 10’は常に真。
[(style)redundantCondition]


■この記事の概要

この記事では、C言語における冗長な条件について解説しています。例としてif(x > 10 && x > 11)のようなコードを挙げ、1つの条件が他の条件を包含するため不要であることを示しています。コードを簡潔かつ効率的に保つための修正方法や、論理演算のショートサーキット動作も説明されています。


■制御が来た時if文は必ず成立する

#include <stdio.h>
void    f1(int x) {
    if(x > 11){
        if(x > 10) //★ここに制御が来た時if文は必ず成立する 
            printf("来る:%s:%d\n",__func__,__LINE__);
        else 
            printf("★来ない1 x=%d\n",x);
    } else {
        if(x <= 11) //★ここに制御が来た時if文は必ず成立する
            printf("来る:%s:%d\n",__func__,__LINE__);
        else
            printf("★来ない2 x=%d\n",x);
    }
}

■制御が来た時if文は必ず成立しない

void    f2(int x) {
    if(x > 10){  
        printf("来る:%s:%d\n",__func__,__LINE__);
        return  ;
    } 
    if(x > 11){ //★ここに制御が来た時if文は必ず成立しない
        printf("★来ない3 x=%d\n",x);
        return ;
    }
}

■第二条件だけで充分

int f3(int x) {
    if(x > 10 && x > 11)//★NG
        return  1;
    return  0;
}


cppcheckとclang-tidyが警告してくれます


■短絡動作

//  cppcheck  --enable=all
#include    <stdio.h>

//お金と暇
char *GOTOtravel(int Money,int freetime) {
    if((Money == 0) || ((Money != 0) && (freetime == 0)))//冗長コード
        return  "止めた";
    return  "行こう";
}
int main(void){
    printf("%s\n",GOTOtravel(0,0));
    printf("%s\n",GOTOtravel(0,1));
    printf("%s\n",GOTOtravel(1,0));
    printf("%s\n",GOTOtravel(1,1));
}

‘x==0 || (x!=0 && y==0)’ は
‘x==0 || y==0’と同じです。

第1条件が成立した時は
第2条件はもう判定する必要がありません。
これを論理演算子の短絡動作と言います。


第1条件が成立しなかった時、
x!=0が確定しているので
第2条件で
x!=0を判定する必要がありません。


➡冗長コードを削除した修正例

//  cppcheck  --enable=all
#include    <stdio.h>

//お金と暇
char *GOTOtravel(int Money,int freetime) {
    if(Money == 0 || freetime == 0)
        return  "止めた";
    return  "行こう";
}
int main(void){
    printf("%s\n",GOTOtravel(0,0));
    printf("%s\n",GOTOtravel(0,1));
    printf("%s\n",GOTOtravel(1,0));
    printf("%s\n",GOTOtravel(1,1));
}

■常に真

warning: overlapping comparisons always evaluate to true

警告: 重複する比較は常に真と評価される
[-Wtautological-overlap-compare]

#include <stdio.h>
#include <stdbool.h>
char *f(bool x){
    if(x == 1 || x != 1){//恒真式
        return  "真";
    }else {
        return  "偽";
    }
}
int main(void){
    printf("%s\n",f(true));
    printf("%s\n",f(false));
}

warning: logical ‘or’ of collectively exhaustive tests is always true
[-Wlogical-op]


■常に偽

#include <stdio.h>
#include <stdbool.h>
char *f(bool x){
    if(x == 1 && x != 1){//恒偽式
        return  "真";
    }else {
        return  "偽";
    }
}
int main(void){
    printf("%s\n",f(true));
    printf("%s\n",f(false));
}

warning: logical ‘or’ of collectively exhaustive tests is always false
[-Wlogical-op]


■数直線上有り得ない

#include <stdio.h>
char *f(int x){ 
    if(x < -100 && 100 < x){
        return  "ここには来ない:数直線上有り得ない";
    }else{
        return  "偽";
    }
}
int main(void){
    for(int x = -127;x<128;x++){
        printf("%s\n",f(x));
    }
}

数直線の上で
-100より小さくかつ
+100より大きい領域はありません。
x ⇦ ー100  100⇒x
NG:if(x < -100  && 100 < x){
OK:if(x < -100  ||  100 < x){
OK:if(-100<=x  &&  x<=100 ){


■数直線上の全域

#include <stdio.h>
char *f(int x){ 
    if(-100 < x || x < 100){
        return  "真";//全部来る:数直線上の全域
    }else{
        return  "偽";
    }
}
int main(void){
    for(int x = -127;x<128;x++){
        printf("%s\n",f(x));
    }
}

数直線の上で
-100より大きいか
+100より小さい領域は全領域です。
-100⇒x x⇦100


参考:

適当に括弧を使おう(使いすぎると、今度は読みにくくなる。良く考えて書こう)

EXP02-C. 論理 AND 演算子および論理 OR 演算子のショートサーキット動作について注意する

MSC12-C. プログラムに対して作用しないコードを検出して削除する
CWE-561: Dead Code
CWE-571: Expression is Always True
CWE-1041: Use of Redundant Code