【C言語】
範囲指定
if(最小値<= X <=最大値)はバグ

if(X

warning: comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning

warning: result of comparison of constant X with boolean expression is always true

警告:if(X<=Y<=Z)に数学的意味はありません

[-Wtautological-constant-out-of-range-compare]
[-Wparentheses]

■if(X<=Y<=Z)で範囲の指定はできない

#include <stdio.h>
const char  *grade(int x){
    if(0    <= x <= 9)     return  "不可";
    if(10   <= x <= 59)    return  "可";
    if(60   <= x <= 79)    return  "良";
    if(80   <= x <= 100)   return  "優";
    return  "採点不能";
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

自然言語に近い表現ですが
意図した動きをしません。

if(0 <= x <= 9)

if((0<=x)<=9

if(論理式<=9)

if(真<=9)か
if(偽<=9)になる

if(1<=9)
if(0<=9)のどちらかになるが、
どちらも、必ず成立する。


■数直線を意識した範囲の指定(推奨)

#include <stdio.h>
const char  *grade(int x){
    if(0    <= x && x <= 9)     return  "不可";
    if(10   <= x && x <= 59)    return  "可";
    if(60   <= x && x <= 79)    return  "良";
    if(80   <= x && x <= 100)   return  "優";
    return  "採点不能";
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

意図した動きをします。
自然言語に近く数直線に近いイメージで
読みやすいと思います。


超える、未満で範囲の指定

#include <stdio.h>
const char  *grade(int x){
    if(-1   < x && x < 10)  return  "不可";
    if(9    < x && x < 60)  return  "可";
    if(59   < x && x < 80)  return  "良";
    if(79   < x && x < 101) return  "優";
    return  "採点不能";
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

意図した動きをしますが
数字が
増えたり
減ったりで理解しずらいかも。


変数を左辺に書く範囲の指定

#include <stdio.h>
const char  *grade(int x){
    if(x >=  0 && x <= 9)     return  "不可";
    if(x >= 10 && x <= 59)    return  "可";
    if(x >= 60 && x <= 79)    return  "良";
    if(x >= 80 && x <= 100)   return  "優";
    return  "採点不能";
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

主語(変数)を左辺に書いたほうが
読みやすいと主張する人も多くいます。


else ifでつないだ範囲の指定

#include <stdio.h>
const char  *grade(int x){
    const char *ret = "採点不能";
    if(x < 0){
        ret =  "採点不能";
    } 
    else if(0 <= x && x <= 9){     
        ret = "不可";
    } 
    else if(10   <= x && x <= 59){
        ret = "可";
    } 
    else if(60   <= x && x <= 79){
        ret = "良";
    }
    else if(80   <= x && x <= 100){
        ret = "優";
    } 
    else {
        ret = "採点不能";
    }
    return ret ;
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

筆者が嫌いな
関数出口一つルールを守った修正例。


最適化した範囲の指定

#include <stdio.h>
const char  *grade(int x){
    const char *ret = "採点不能";
    if(x < 0){
        ret =  "採点不能";
    } 
    else if(x <= 9){     
        ret = "不可";
    } 
    else if(x <= 59){
        ret = "可";
    } 
    else if(x <= 79){
        ret = "良";
    }
    else if(x <= 100){
        ret = "優";
    } 
    else {
        ret = "採点不能";
    }
    return ret ;
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

最適化した修正例ですが、
if文の順番を変えると
意図した動きをしなくなります。


gccの拡張機能を使った範囲の指定

#include <stdio.h>
const char  *grade(int x){
    switch(x){
    case 0 ...   9: return  "不可";
    case 10 ... 59: return  "可";
    case 60 ... 79: return  "良";
    case 80 ... 100:return  "優";
    default:        return  "採点不能";
    }
}
int main(void){
    for(int i = -1 ; i<=101;i++){
        printf("%3d点は%s\n",i,grade(i));
    }
}

自然言語に一番近い分かりやすい表現ですが、
gcc/clangの拡張機能です。

拡張機能は
使用が禁止されている業界もあります。

参考:

EXP13-C. 関係演算子および等価演算子は、結合則が成り立たないものとして扱う