C言語の論理表現

今日こんなバグに遭遇した。

if (TRUE == checkFunc(hoge, fuga)) {
       /* チェックがOKだった場合の処理 */
}

このチェック関数の戻り値が問題でチェック関数はTRUE/FALSEでは無くSUCCESS/FAILUREを返すようになっていたのだ。そしてその定義は
TRUE:1, FALSE:0, SUCCESS:0,FAILURE:0以外のエラーコードがいろいろとなってた。
もちろんチェックがすべてOKだった場合にはSUCCESSである0が返されてTRUEと比較されチェックOKだった場合の処理が行われないわけである。TRUE/FALSEを返すか、SUCCESS/FAILUREを返すかはコーディング規約などで統一しておくべきであろう。今参加しているプロジェクトはコーディング規約が整備されていない。


C言語特有の問題としては言語仕様として偽は0なのであるが真は非0である。!演算子の定義より!0を評価すると1となるし確かに1は真である。しかし、2も3も4も0以外はすべて真である。値としての真は定義不可能である。1はあくまでも真の代表値のひとつでしかない。C言語でTRUEを見たら警戒しなくてはいけない。1以外に定義されている可能性がある。(もっともTRUEを0,FALSEを1と定義した超絶コードを見たことがあるのでこれも含めて注意。ただしCではなくVBだったような気がする。馬鹿かと、アホかと、boolean使えよと。モニタの前で悶絶した)


似たような話で、C言語では有効なポインタかどうかは判定できない。無効なポインタかどうかは判定できる。NULLと比較すればよい。それと同じように真のある値と等しいかどうかは判定出来ないので偽かどうかで判定しなくてはならないのである。であるからTRUEと比較するようなコードを見たら常に注意が必要だ。そんなコードは本来は書いてはならない。チェック関数などがブール値を返すようにすれば比較の必要は無い。ついでに関数名はどういう条件で値が返ってくるのか明示するような名前すべきだ。たとえば

if (isOkCheckParam()) {
       /* OKの場合の処理 */
}

などという名前の関数にして適正なパラメータのとき非0を返すようにする。逆にエラーの場合に非0を返すときはエラー処理をしたい場合などである。

if (isErrParam()) {
       /* エラー処理 */
}

C言語の常識としては関数は正常、成功だと0を返す。(何言語の常識化知らないがそうしない香具師もいる、、、)よって、

if (checkFunc(hoge, fuga)) {
       /* エラーだったときの処理 */
}

ならCネイティブにとっては問題なかったと思われる。