トップページ

本棚


両手で1000まで数えられますか?:2進法の話
数値 - 危険物取り扱い注意
100 × 200 =32?:変数のオーバーフローの話
パリティビット
小数の扱いについて
ぽいんた
ぽいんた2
ぽいんた3
ジ・オリジン
ジ・オリジン:補足
かっこつける話
かっこつける話2
文字列のこと
タイミングの話
拡張性の話
取り込む話
staticな話

コンパイルの話1
コンパイルの話2:止まらぬビルド
コンパイルの話3:マシン語に落ちるということ1:メモリの話
コンパイルの話4:マシン語に落ちるということ2:最適化
コンパイルの話5:マシン語に落ちるということ3:変数とスタック
コンパイルの話6:コンパイラはそもそも何をやってくれるのか??
リンクの話
プリプロセッサの話

OS、というもの

オブジェクト指向1
オブジェクト指向:2
オブジェクト指向:3

オブジェクト指向:番外 C言語のソースファイルの話
オブジェクト指向:番外 C言語での「再利用性」と「カプセル化」データ構造とアルゴリズム


抽象的な話

寝込んで布団の中で考えたこと
こんなの、常識??
お仕事プログラミング
ソフトでハードなプログラム
プログラムするということ
お勉強
プログラムを学ぶということの補足
C言語:「学問」と「実務」
統合開発環境
C言語ってポータブルですか?
C言語ってポータブルですか?:2
あなたは、どう読みますか?
ああ勘違い
試してガッテン
低級品
質問をするということ
ポカ
「何もしない」 != 「無駄」
エディタの話
もっと手を抜こう

いまどきの、アセンブラ

VisualStudio2005
VisualStudio2005:2

戦争の防ぎ方、に対する私の考え
身近な差別
改革
地球に優しいなんて大嘘
統計で嘘をつく方法

言葉について
言葉について:2

神が死んだということ
善悪の彼岸から、力への意思を目覚めさせるということ

本を読むということ
本を読むということ:2

絵を描く話
地図
地球儀

オカルトのお話
がんだむさん
RPGソフトウェア
記紀神話の不思議



メニュー

※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

コンピュータの中では、数値はすべて2進数で表されるのでした。

そして、負数は最上位bitがOnとなった、2の補数表記で表されるのでした。


では、例えば
signed char c;
signed int i;

c = -1;	/* 0xff */
i = c;
のようなコードを書いた場合、どうなるのでしょう。

32bit環境ならば、当然intは32bitです。残りの24bitはどうやって埋めるのでしょう?


この場合、「符号拡張」が起こります。符号付(signed)な値の場合、より大きな型に代入する際には上位24bit分には代入する数値の符号で埋められます。上の例だと、-1は0xffとなり、符合は1です。したがって、上位24bitが1で埋められ、0xffffffffとなるわけです。

これは32bitの場合での2の補数表記となっており、辻褄があっています。


問題は、この符号拡張がプログラマが意識していないタイミングで行われることがあるということです。

例えば、
#define HOGE (0xff)
signed char c = 0xff;
・・・
switch(c)
{
case HOGE:
  printf("HOGE!\n");
break;
default:
  printf("PIYO!\n");
break;
}
などとした場合、正しく評価されません。おそらく、「HOGE」と表示されることは無いでしょう。

また、同様に
char c;
signed char* cp;

c = -1;
cp = &c;

if (*cp == 0xff)
{
  ・・・
}
などという使い方も危険です。


なぜならば、(処理系にもよりますがANSIでは)switchステートメントで評価する際にはintとして扱うので上記の符号拡張が行われてしまうのです。
また、*演算子を使用して取り出したポインタの指し先が保持している値もintで評価されてしまうことがあるからです。

つまり、switch(0xffffffff) if(0xffffffff == 0xff)で評価されてしまうため、0xffと一致しなくなってしまうのです。

これを避けるためには、このような使い方をする変数は明示的にunsignedとして宣言するなどをすることです。
上の例ではあえてsignedで宣言していますが、signed/unsignedをつけないで宣言した変数(単にchar cなどとした変数)が符号付か符合なしかは処理系依存です。運がよければ正常動作しますが、移植性は損なわれてしまいます。


C言語はいくつかのサイズの違う型を扱うことができます。
その際に、このような変換をコンパイラがすることがあるのです。

これを、「暗黙の型変換」といいます。
おおむね、いちいちキャストしたりしなくていいので便利なのですが。

上の例のような場合には注意が必要です。


また、符号の有り無しで同じサイズの変数でも値域が異なることにも注意しなくてはいけません。

例えばcharの場合、signed char は-128~127、unsigned charなら0~255の値域を持つわけで。
signed char sc = 100;
unsigned char uc = 100;
としたとき、sc * 2 は -56、uc * 2 は 200(どちらも0xc8)となってしまいます。同じ1byteでも符号に注意しないと、結果に思わぬ値が入ってしまうわけです。


ソースコードだけを見ていると、ここで述べたようなことで何らかのバグを出したとしてもなかなか気づくことができません。
ですが、プログラムで扱うデータというのは、内部的にはすべからく数値として扱われています。
したがって、ここで述べたようなことに留意するかしないかで、その人の作るプログラムの質が大きく変わってくると思います。




| 新しいページ | 編集 | 差分 | 編集履歴 | ページ名変更 | アップロード | 検索 | ページ一覧 | タグ | RSS | ご利用ガイド | 管理者に問合せ |
@wiki - 無料レンタルウィキサービス | プライバシーポリシー