rakushoo blog

ジャズとプログラミングがやりたい人

memcmp,strcmpの戻り値の絶対値にハマった話

「標準関数を再実装する」という課題でstrcmpにハマった話です。

引数の入力のしかたによって、戻り値が異なる

スクールの他の生徒から質問を受けて???となった動作がありました。

int main()
{
    char s1[] = "5";
    char s2[] = "1";
    int a = strcmp("5", "1");
    int b = strcmp(s1, s2);

    printf("strcmp: %s, %s -> a:%d b:%d\n", s1, s2, a, b);
    return 0;
}

<出力結果>
strcmp: 5, 1 -> a:1 b:4

テストケースを作るのに、直接、値を代入した時と別変数に取った時で結果が違う、とのことでした。確かにこれは不思議。
"5" と "1" を比較して期待する結果は 4 かと思います。
となると、引数に直接値を指定すると得られる 1 は何者?となりました。

memcmpに置き換えても同じ動作だったのでひとまずstrcmpについて調べます。

そもそも仕様で戻り値の絶対値は言及されていない

いろいろ試しましたが、

  • 引数をポインタで渡すと、戻り値の絶対値は比較文字の差分と一致する
  • 引数に値 "5" を直接渡した場合は、戻り値が1/0/-1となる
  • const char s1[] = "5"; と定義した場合も同様の結果。

つまり、const無しの入力では値の差分が戻り値に反映されますが、constに対しては、値の大小比較はできるが差分は算出できない、ように見えました。

改めてstrcmpの仕様を見ると、

The strcmp() and strncmp() functions return an integer greater than, equal to, or less than 0, according as the string s1 is greater than, equal to, or less than the string s2.

戻り値は、正の数・負の数、と記述されており、その絶対値についての言及がされていませんでした。推測するに、constの入力は値の比較はできるが差分は算出していないようです。

これからは、memcmp/strcmp の戻り値は正負だけを利用するようにします。