[迷信] isalpha 関数の引数は char 型

isalpha 関数に限ったことではありませんが、<ctype.h> ヘッダで宣言される is 系関数は、次のように int 型の引数を取ります。

int isalpha(int c);

このこと自体もよくある間違いなのですが、問題はここからです。すなわち、is 系関数の引数が char 型だと事実誤認しているために、あるいは int 型であることを知っていたとしても、実引数として渡すことができる値に制約があることを知らないために、危険なコードを書いてしまうことがよくあるのです。

is 系関数に実引数として渡すことができる値は、0 ~ UCHAR_MAX または EOF だけです。通常は問題ないのですが、多バイト文字を含む文字列の各要素を順に is 系関数で調べる場合などは、is 系関数に負の値を渡してしまうことになります。

そうです。char 型が符号付きか符合無しかは処理系定義ですので、char 型が符号無しの環境でたまたま動いていたとしても、char 型が符号付きの環境に移植したとたん、不可解な動作をしたり、クラッシュしたりすることになるのです。

is 系関数に渡す実引数は、fgetc 関数の返却値のような場合はそのままで構いませんが、char 型の値を渡すときには、明示的に unsigned char にキャストしなければなりません。

const char str[] = "abc123";
for (char* s = str; *s != '\0'; s++)
{
  if (isalpha(static_cast<unsigned char>(*s)))
  {
    ...
  }
}

分かっていてもよく間違うもので、特に、述語として is 系関数をアルゴリズム関数に渡す場合など、コールバックでは要注意です。

トラックバック


URL から "-nospam" を削除してトラックバックを送信してください。

4行目は*sでなくてsじゃないでしょうか?

4行目は*sでなくてsじゃないでしょうか?

s でなくて *s

s でなくて *s と逆に質問して、訂正されて訳が分からなくなったのかな?
結局、現在の *s が正しいのですよね。

本当ですね

まあ、指摘された箇所が間違っていたことは確かですので直しておきました。
本文中に修正履歴を入れると読みにくくなるので、跡は残していません。
*sが正解です。

サンプルプログラムは可能な限り動作確認をしているのですが、HTMLに直すときに失敗することがときどきあります。
今回もそのひとつではないかと思います。

ご指摘ありがとうございます。

その通りです。修正しておきます。

このエントリーを含むはてなブックマーク