【C言語】
文字列を比較する関数 strcmp()の戻り値は true/falseじゃない

warning: function ‘strcmp’ is compared to a suspicious constant

警告:strcmpの戻り値を0以外と比較するのは疑わしい
[misc-suspicious-string-compare]


■1.strcmpをtrue/falseと比較するのは間違い

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
void f(char *s1,char *s2) {
    if (strcmp(s1,s2)==true)     
        puts("同じ");  
    else                         
        puts("違う");
    if (strcmp(s1,s2)==false)    
        puts("違う");  
    else                         
        puts("同じ");    
}

strcmpの戻り値はtrue/falseではありません。


■2.strcmpは0と比較するのが正しい

void g(char *s1,char *s2) {
    if (strcmp(s1,s2) == 0)     
        puts("同じ");  
    else                        
        puts("違う");
    if (strcmp(s1,s2) != 0)     
        puts("違う");  
    else                        
        puts("同じ");    
}

strcmpの戻り値は第1引数と第2引数の差分です。
第1引数と第2引数が等しい時、
差分無し、すなわち0が返ります。


■3.うっかり0と比較するのを忘れる

(warning): The expression ‘strcmp(p,”def”) != 0’ is suspicious. It overlaps ‘strcmp(p,”abc”) == 0’.

警告:第2条件で==0が抜けているかも[(warning)overlappingStrcmp]

#include <stdio.h>
#include <string.h>
int f(char *p) {
    if(strcmp(p,"222") == 0 || strcmp(p,"333"))
        return  1;
    return  0;
}
int g(char *p) {
    if(strcmp(p,"333"))
        return  1;
    return  0;
}
int h(char *p) {
    if(strcmp(p,"222") == 0 || strcmp(p,"333") == 0)
        return  1;
    return  0;
}

strcmp()は第1、第2引数が同じ時0を返しますが、
うっかり0と比較するのを忘れる場合があります。
この例では関数f()は関数g()と同じ動きをしますが、
関数h()のように書きたかった可能性があります。


■4.strcmpと似た関数を作ってはいけない

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
bool IsStringSame(char *s1,char *s2) {
    if(!strcmp(s1, s2)) return  true; 
    else                return  false;
}
bool IsStringDiff(char *s1,char *s2) {
    if(strcmp(s1, s2))  return  true;
    else                return  false;
}
void g(void) {//似た使い方をする者が現れる
    if (IsStringSame("abc", "abc")==0) 
        puts("同じ");  
    else                            
        puts("違う");
    if (IsStringDiff("abc", "def")!=0) 
        puts("違う");  
    else                            
        puts("同じ");    
}

strcmp()と似た関数を作る者が現れると
strcmp()と似た使い方をする者が必ず現れる。

つまり、
関数g()では==0や、!=0を記載しなくても良いのに、
strcmp()と同じように使ってしまう者が必ず現れる。


■5.まとめ

●if(strcmp(s1,s2)==1は多分バグ
●if(strcmp(s1,s2)== 0)の誤解しやすい読み方
「もしs1とs2の比較結果が偽(0)ならば」
●if(strcmp(s1,s2)== 0)の推奨する読み方
「もしs1とs2の差分が無(0)ければ」
●文字列が等しい時 true(1) を返す自作関数を作ってはいけません

参考:

C-FAQ 17.3

http://www.kouno.jp/home/c_faq/c17.html#3

CERT-C  EXP20-C

https://www.jpcert.or.jp/sc-rules/c-exp20-c.html