第7章 キャストとデータ変換連載 改訂版 C#入門(3/5 ページ)

» 2002年10月02日 00時00分 公開
[川俣晶(http://www.autumn.org/)(株)ピーデー(http://www.piedey.co.jp/)]

7-6 符号の有無は要注意

 キャストを用いる際には、符号付きのデータ型と、符号なしのデータ型の違いに注意を払う必要がある。例えば、同等のビット数で表現されるデータ型の間で変換を行う場合、確かに情報が欠落せずに変換はできる。しかし、それが指し示す値が同じとは限らない。List 7-8に一例を示す。

  1: using System;
  2:
  3: namespace Sample008
  4: {
  5:   class Class1
  6:   {
  7:     [STAThread]
  8:     static void Main(string[] args)
  9:     {
 10:       short i = -1;
 11:       ushort u = (ushort)i;
 12:       Console.WriteLine("{0},{1}",i,u);
 13:     }
 14:   }
 15: }

List 7-8

 これを実行した結果はFig.7-8のようになる。

Fig.7-8

 変数iと変数uは、機械語レベルで格納されるビットの値としてはまったく同一であり、ビット単位で処理する演算子を用いるとまったく同じ結果になる。しかし、数値としての値は同じではないことを肝に銘じておく必要がある。いい換えれば、符号付きと符号なしのデータ型は違うものだと認識して、混用はなるべく避けるほうがよい。

7-7 小数の切り捨て

 いうまでもなく、整数型には小数を表現する能力はない。キャストによって実数型から整数型に変換させることはできるが、その際、小数点以下の値はすべて失われる。では、小数点以下が消えてなくなるときに、その値は変換結果にどんな影響を及ぼすのだろうか? 切り捨てだろうか? 切り上げだろうか? 四捨五入だろうか?

 実際に試してみよう。サンプル・ソースList 7-9を実行すると、そのことが分かる。

  1: using System;
  2:
  3: namespace Sample009
  4: {
  5:   class Class1
  6:   {
  7:     [STAThread]
  8:     static void Main(string[] args)
  9:     {
 10:       for( float f=-2; f<2; f += 0.25f )
 11:       {
 12:         int i = (int)f;
 13:         Console.WriteLine("{0},{1}",f,i);
 14:       }
 15:     }
 16:   }
 17: }

List 7-9

 これを実行するとFig.7-9のようになる。

Fig.7-9

 見て分かるとおり、実数から整数にキャストで変換する場合は、「小数点以下を切り捨てる」ということになる。四捨五入に慣れたVisual Basicプログラマーなどは要注意である。

7-8 参照型のキャスト

 クラスからnewによって作成したインスタンスも、キャストの対象になる。例えば、サンプル・ソースList 7-10では、ソース内で宣言したクラスであるClass1のインスタンスをobject型にキャストしている。objectは、すべてのクラスの共通のベースとなるクラスなので、すべてのクラスのインスタンスは、objectにキャストできる。

  1: using System;
  2:
  3: namespace Sample010
  4: {
  5:   class Class1
  6:   {
  7:     public String hello;
  8:     [STAThread]
  9:     static void Main(string[] args)
 10:     {
 11:       Class1 c = new Class1();
 12:       c.hello = "Hello!";
 13:       object o = (object)c;
 14:       Class1 c2 = (Class1)o;
 15:       Console.WriteLine("{0},{1}",c.hello,c2.hello);
 16:     }
 17:   }
 18: }

List 7-10

 このソース・コードで問題になるのは、14行目だろう。一度object型にキャストしたものをもう一度キャストして、もとのClass1型に戻している。もし、object型にキャストされたときに、インスタンスがobject型に変換されているなら、Class1の内部で宣言したhelloという変数はその時点で失われるはずである。そのため、再びClass1にキャストしても、helloに代入した「Hello!」という文字列は失われているはずである。しかし実行結果はFig.7-10のようになる。

Fig.7-10

 つまり、13行目でobjectへキャストされても、変数helloの値は残っているということである。そして、14行目で再びClass1型にキャストされた時点で、変数helloへのアクセスは再び可能になる。

 これが、キャストによってデータが失われたら永遠に戻らない整数型などの値型と、クラスなどの参照型の違いである。参照型は、objectなどのスーパークラスにキャストしても、もとの型に再キャストすれば、完全にもとどおりの機能を取り戻す。

 

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。