スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


このエントリーをはてなブックマークに追加

charの落とし穴 - 暗黙の型変換と符号拡張

変化というものは、たとえ良い方向に変わっているときでさえ、常に障害と不快がともなう。
アーノルド・ベネット
前回unsignedでよく陥りがちなバグについて触れました。今回はその続編で、char型での落とし穴として、いわゆる符号拡張(sign extension)と暗黙の型変換(inplicit conversion)について説明します。

次のコードの問題点はわかるでしょうか?
typedef char value_t;
#define INVALID 0xff

/* valがINVALIDなら0、それ以外で1を返す */
int
check(value_t val)
{
  switch (val) {
  case INVALID:
    return 0;
  default:
    return 1;
}
一見問題なさそうに思えますが、実際このコードをコンパイルして、valにINVALID(0xff)を指定しても1が帰ってきます。なぜでしょう?

C言語のswitch分では、比較値はint型として扱われます。よって、valがswitchに渡されるときに、valの値はint型に暗黙の内に拡張されます。変換時には符号拡張が行われ0xff(charの-1)は0xffffffff(intの-1:intが32bitの場合)となってしまいます。よって、0xffとは一致しないのです(※1)。

これは上の例の用に、charをtypedefした型と、#defineで定義したマクロ値で、列挙型のような使い方をしようとした時に起こりがちなバグです。列挙型(enum)だとint相当でサイズが4byteになってしまうということで、このような使い方はよく見かけます。回避策としては、value_tをunsigned charでtypedefすることです。unsignedであれば、符号拡張はされないので、bitパターンはそのまま保持されます。

※1 charが符号付きかどうかは処理系依存です。動作することもあります。

【関連記事】
unsignedの落とし穴
テキストとしてのコーディング規約
warningに気を配る

【関連書籍】
Cプログラミングの落とし穴 A.コーニグ
CプログラミングFAQ―Cプログラミングのよく尋ねられる質問 スティーブ・サミット
プログラミング言語C ANSI規格準拠 B.W.カーニハン D.M.リッチー
独習C ハーバート・シルト


このエントリーをはてなブックマークに追加

コメントの投稿

非公開コメント

人気エントリ
最近の記事
本のおすすめ

4274065979

4844337858

482228493X

4904807057

4873114799


最近のコメント
Links
プロフィール
  • Author:proger
  • 組み込み関係で仕事してます
ブログ内検索
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。