2007年12月22日

strchr() ではまった話

標準Cライブラリに strchr() という関数があります。文字列の先頭から指定した文字を探すという単純な関数なのですが、先日、意外な仕様を知りました。

 

以下のコードを見てみます。

  if (strchr("+-*/", c)) {  // c は四則演算の記号かな?
    ...
  }

この if 文は c が + - * / のいずれかの場合に条件が真となり、ブロック中が実行されます。…と、思いきや、実は条件が真になるケースがもうひとつありました。c が '\0' の場合です。

まさかと思って手元の Linux の man を見ると、文字列の終端のナル文字 ('\0') の扱いは明記されていません。

The strchr() function returns a pointer to the first occurrence of the character c in the string s.

そこで The Single Unix Specification のマニュアルの strchrの項を見てみると、次のように記述されていました。

The strchr() function shall locate the first occurrence of c (converted to a char) in the string pointed to by s. The terminating null byte is considered to be part of the string.

というわけで、文字列の末尾の '\0' は文字列の一部とみなされるようです。strchr() を使って文字の種類を検査するコードは結構あると思うのですが、上のように書くと、 '\0' はすべて検査を通ってしまいます。これはなかなか厄介なバグの元になりそうです。

C++ で std::string を使っている場合は、 s.find_first_of("+-*/") != string::npos が使えます。

まとめ

strchr() が文字列終端のナル文字を含めて探索するということを今頃になって知りました(常識かもしれませんが)。単純そうに見える関数でもなかなか奥が深いものです。ちなみに、The Single UNIX Specification のマニュアルを読むには Firefox の SUSv3検索プラグインが便利です。