暗黙の型変換と符号拡張とは?

   
暗黙の型変換と符号拡張とは?

C言語を勉強してきた中で私の致命的な思い違いシリーズの第二弾です。

今回は、暗黙の型変換と符号拡張についてです。

暗黙の型変換と符号拡張で起きる問題

次のコードの出力結果はどうなるでしょうか?

#include<stdio.h>

int main(){

	char c = -1;

	printf(" c %d,%x,%dn",sizeof(c),c,c);

	return 0;
}

答えは以下の通りです。

$ ./test.exe
 c  1,ffffffff,-1

この結果、初めは何もおかしくないと思っていました。

しかし、よく考えるとおかしな点が2点あります。

  1. 1バイト分の2桁表示となるはずが、4バイト分の8桁表示になっている
  2. 1バイト分は右2桁がffでも納得できるが、あと3バイトが勝手にffffffになっている

1バイトが4バイトで表示される疑問

char型の変数cは1バイトであるはずです。その証拠にsizeof(c)を行った際の値は1。しかし、変数cを%xでprintfした結果が4バイト分8桁表示されています。想定していたのはffのみです。それがffffffffと表示された事に疑問を抱きました。

なぜ4バイト分表示されたかの謎は調べたらすぐにわかりました。printfは引数がint型としているので、char型を引数に入れても暗黙のうちに型変換が生じ、int型として4バイト8桁で表示されたのです。

ちなみに、この現象を暗黙の型変換と言うそうです。

暗黙の型変換時に3バイトがfで埋められている疑問

もう1つの疑問です。1バイトが4バイトで表示されるのは暗黙の型変換が生じているという理由で納得しました。では何故000000ffではなくffffffffなのでしょうか?

これはchar型がsignedかunsignedかによって左右されるようです。実験的に下記のコードを試してみました。

#include<stdio.h>

int main(){

	signed char c = -1;
	unsigned char uc = -1;

	printf("  c %d,%08x,%dn",sizeof(c),c,c);
	printf(" uc %d,%08x,%dn",sizeof(uc),uc,uc);

	return 0;
}

手元で動くサンプルをダウンロード(126KB)

結果は以下でした。

$ ./test2.exe
 c  1,ffffffff,-1
uc  1,000000ff,255

signedの場合、暗黙の型変換時に拡張された3バイト分がfで埋められていて数値として-1になります。unsignedの場合は3バイト分が0で埋められていて数値としては255になります。ちなみに-1と255のビットパターンは同じでsignedかunsignedかによって数値の表示が変わることは、さすがに知ってました。(でもコンパイル時にunsigned char型の変数に-1を代入しようとしてwarningも出ないことにはびっくりしましたけどね)

この結果から符号の整合性を保つために型変換した際の3バイト分を、ffffff又は000000とすることで数値としての整合性を保っています。

この現象を符号拡張と言うそうです。

まとめ

今回のような、暗黙の型変換や符号拡張を知らないと、何が正しく、何がおかしいのか正確に判断できないので1人では何も解決できなくなってしまいます。C言語には落とし穴がいっぱいですね。

Page Top