【C言語】
ヨーダ記法はもう古い?
-C言語で安全にif(x=0)エラーを防ぐ-Werrorオプション-

warning: suggest parentheses around assignment used as truth value 

警告:真偽値として使用するなら代入式にカッコつける
[-Wparentheses]

■この記事の概要

この記事は、C言語における「ヨーダ記法」を解説し、if(x=0)の書き間違い防止策として
-Werrorオプションを使う方法を提案しています。

ヨーダ記法の賛否や時代に適したプログラミング手法についても論じています。


■これがヨーダ記法

if(ret == ERROR)//音読できる

if(ERROR == ret)//音読できない⇦これがヨーダ記法

世界的に有名なコーディングルール CERT-C には
「EXP21-C. 等価比較の左側に定数を配置する」
https://www.jpcert.or.jp/sc-rules/c-exp21-c.html
という推奨ルールがありましたが
2022年9月現在、本家米国のCERT-Cでは
https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard
EXP21-Cはになりヨーダ記法の推奨はありません。


■代入【=】と比較【==】の書き間違い

int f(int  x)
{
    if(x = 0) { //最近のコンパイラは警告してくれる
        return  0 ;
    }
    return  1;
}

C言語の代表的な間違いに == と = の書き間違いがあります。
この間違いを防ぐために 定数を左辺に記述する記法があります。
これをヨーダ記法と言います。
しかしヨーダ記法は読めないコードを量産するため反対派と賛成派が何十年も争って来ました。
試しに以下のコードを声に出して音読してみましょう。

if(NOT_ERROR != ret)  //音読できますか?

やはり品質のためなら読めないコードを量産しても良いという考えは時代遅れではないでしょうか?


■音読できない【ヨーダ記法】

int f(int  x)
{
     //読みづらい「ヨーダ記法」は時代遅れとなった
    if(0 == x){        
        return  0;
    }
    return  1;
}

現代では不自然なヨーダ記法を使うのではなく 
gcc -Wall -Wextra -Werror のようにコンパイラの警告オプションを使ってケアレスミスを刈り取る手法が主流となりつつあります。
-Werror オプションを付けると警告をエラーに格上げするため疑わしいコードはコンパイルできなくなるので警告の見落も無くなります。


とはいえ下記に示すようにコンパイラが全ての間違いを見つけてくれるわけではないので注意が必要です。

■意図的か間違いか判断できない例

static  int func()
{
    return  1;
}
int f(void)
{
    int ret ;
    if(ret = func()){   //warning: suggest parentheses around assignment used as truth value [-Wparentheses]
        return  1;
    } else {
        return  0;
    }
}

■意図的な場合の警告抑止方法

int f(void)
{
    int ret ;
    if((ret = func())){ //代入式を丸かっこで囲むと警告されなくなる
        return  1;
    } else {
        return  0;
    }
}

代入式を丸カッコで囲むと
gccとclangは意図的と 判断して警告を出さなくなります。

この機能はC言語の仕様ではないので
msvc等では警告は抑止されません。


■gccでも間違いを指摘してくれない例

int f(int  x,int   y)
{
    //でも、丸かっこで囲まれた(y = 1)は
  //意図的みなしgccは警告しないので注意
  if((x == 0) && (y = 1)){ 
        return  0 ;
    }
    return  1;
}

第二条件の代入は丸カッコで囲まれているので意図的と見なされ
gcc コンパイラも指摘してくれないので注意が必要


参考:

EXP45-C. 選択文に対して代入を行わない

CWE-481: Assigning instead of Comparing

/WX コンパイラ警告をすべてエラーとして扱います。

■アンケート

14
ヨーダ記法利用状況を教えてください