l_n_m’s diary

よわい電気系の日記(本当にただの日記)

余計な符号拡張

符号拡張

まず符号拡張ってなんぞや? ってところから
例えば16bitの値があったとします。
1000100010001000
でいいや。
これを32bit、つまり1byteの数字として扱いたいとしましょう。では、これは上に0をくっつけて、
00000000000000001000100010001000
でいいのでしょうか?

いい場合もあれば、悪い場合もあります。
2の補数表現をしている場合、最上位bitが1ならその数字は負の数です。それに0を補ってしまうと、正負が変わってしまいます。値も変わってしまうけれどそこの説明は省略。よく考えれば分かることだし。

というわけで、最上位が1ならば1を補って、
11111111111111111000100010001000
とするのが符号拡張です。
C言語で言うunsigned(符号なし)では、いつでも0を補えばOKです。

同様に、1byteしかないchar型を4byteのint型として解釈するときにも符号拡張したりしなかったりします。というか自動で符号拡張されます。その話をこれから。

charを扱う

C言語で文字を表すchar。へーきへーきwと思っていたら落とし穴がありました。
UTF-8で3バイト文字の「七」を解釈したとき、「0xe4b883」となるはずです。しかし、それぞれの文字(e4, b8, 83が出てくるはず)を表示させると、
ffffffe4, ffffffb8, ffffff83
と表示されてしまいます。

しばらく悩んでいましたが、ネットで調べてみたら符号拡張のせいだと判明しました。
1byteしか無いchar型をint型の整数として扱うとき、内部で4byteに拡張してから使います。char + intは、内部でint + intにされています。それはそう。
さて、お気づきかとは思いますが、char型の変数の最上位bitが1だったら?

そう。0xe4 = 0b11100100ですから、最上位bitが1。
符号拡張されて11111111111111111111111111100100となってしまいます。
そのせいで余計なfがいっぱい出てきていたわけですね。

解決

さて、そうと分かれば話は早い。char型ではなくunsigned charとして扱ってやればOKです。符号拡張されず、上3byteは0で埋められます。

漢数字を数字に変換するプログラムなんかでは必要な知識ですね。
というわけで、符号拡張の落とし穴でした。
アルファベットとか数字とかを扱っている分には全く影響無いので、昔プログラムに慣れていない頃には気付くこともありませんでした。問題にならなければ気付きようがないもの。