<ctype.h> から無害に見える関数を取得するとしますisupper()
。
定義されていint isupper(int c);
ます。したがって、int を取り、int を返します。
ここで、あなたがあまり注意深いプログラマーではなく、この関数に char を渡すだけだとしましょう。「何がうまくいかないんだろう? これは私が知っている最も単純な関数だ!」と思います。
しかし、あなたは間違っているでしょう。どこかで、このひどい間違いのために、誰かが彼女の MP3 プレーヤーを無限のクラッシュ ループに陥らせるでしょう。
その理由は次のとおりです。C で最も面倒な型は char です。署名することも、署名しないこともでき、コンパイラを何らかの方法で強制することもできます (ただし、別のワームを開くこともできます)。さらに最悪なのは、標準 C ライブラリがこの型をあらゆる場所で使用しているということです!
したがって、char を使用しますが、それが実際に環境で署名されているという事実を認識していません。世界が ASCII の世界であるかのように使用します。
しかし、世界はそうではありません。そして、その MP3 の幸せな所有者は、名前に文字 ä (「拡張 ASCII コード 132」) が含まれるドイツの有名な曲を聴いています。
この文字をisupper()
に渡すと、コンパイラは次のような恐ろしいことをします。整数に変換して渡す. どうすればよいですか? C 標準を確認してみましょう... うーん... 簡単です、値を取得して符号拡張するだけです (char は符号付きなので、わかりませんか?) . さて、この文字の値は -124 なので、-124 の値を持つ int に変換するだけです. これは簡単なことでした. 何が問題なのかわかりません. なぜプログラマーに警告する必要があるのでしょうか? !」
そしてisupper()
、132 の代わりに -124 で呼び出されるようになりました。
しかし、それの何が問題なのですか?コンパイラに付属の C ライブラリがisupper()
単純な 128 バイト配列を使用して実装することを除いて、何もありません。指定されたインデックスで値を返すだけです。配列は、1 である大文字の ASCII コードを除いて、どこでも 0 で初期化されます。このようなシンプルで洗練された実装...
この関数に負の値を渡すとどうなるでしょうか。まあ、それは許可されていません:
c 引数は int であり、その値は unsigned char として表現できる文字、またはマクロ EOF の値と等しいことをアプリケーションが保証する必要があります。引数が他の値を持つ場合、動作は未定義です。
したがって、未定義の動作。この場合、プロセスに属さないメモリにアクセスしようとし、BAM! プログラムがクラッシュします。
つまり、char は悪であり、適切に使用する方法を本当に理解していない限り、決して使用すべきではありません。
(*) Keith Thompson がコメントで述べたように、使用を避けることはもちろん不可能char
です。からstrlen()
までcurl_easy_escape()
、誰もが を使用しchar
ます。int
ただし、特にchar
が負の数を保持している可能性がある場合は、への変換に注意する必要があります。<ctype.h> 関数と配列インデックスは、コストのかかる間違いを犯しやすい 2 つの場所です。