こんにちはー!ニアです。
先ほど書いた「浮動小数点型の数値はメモリ上でどのように格納されているのか」では、浮動小数点型(float型など)の数値がメモリ上でどのように格納されているかを調べていきました。
では、.NET Frameworkのdecimal型の場合はどうでしょう・・・
1. メモリ上での並び順を調べる
C#で数値のメモリ上での並び順を調べる時は、BitConverterクラスのGetBytesメソッドを使用します。取得したbyte型配列の要素の並び方は、メモリ上での並び方と同じです。
using System;
using System.Linq;
class Program {
static void Main( string[] args ) {
Console.WriteLine( "バイトオーダー : {0}方式\n", BitConverter.IsLittleEndian ? "リトルエンディアン" : "ビッグエンディアン" );
int i = 0x01020304;
byte[] ib = BitConverter.GetBytes( i );
Console.WriteLine( "int型" );
Console.WriteLine( "元の値 : {0:X8}", i );
Console.WriteLine( "メモリ上の値 : {0}\n", string.Join( " ", ib.Select( _ => _.ToString( "X2" ) ) ) );
float f = 1.024f;
byte[] fb = BitConverter.GetBytes( f );
Console.WriteLine( "float型" );
Console.WriteLine( "元の値 : {0}", f );
Console.WriteLine( "内部表現の値 : {0:X8}", BitConverter.ToInt32( fb, 0 ) );
Console.WriteLine( "メモリ上の値 : {0}", string.Join( " ", fb.Select( _ => _.ToString( "X2" ) ) ) );
}
}
◆ 実行結果
バイトオーダー : リトルエンディアン方式
int型
元の値 : 01020304
メモリ上の値 : 04 03 02 01float型
元の値 : 1.024
内部表現の値 : 3F83126F
メモリ上の値 : 6F 12 83 3F
decimalの場合
しかし、BitConverterクラスのGetBytesメソッドには、decimal型用のオーバーロードがありません。代わりに、ポインタを使って直接変数にアクセスしていきます。
内部表現はdecimalのGetBitsメソッドを使って取得します。
using System;
using System.Linq;
class Program {
static unsafe void Main( string[] args ) {
decimal d = -0.4972397250606885993375668763m;
Console.WriteLine( "元の値 : {0}", d );
Console.WriteLine( "内部表現の値 : {0}", string.Join( " ", decimal.GetBits( d ).Reverse().Select( _ => _.ToString( "X8" ) ) ) );
// byte型ポインタにdecimal型変数のアドレスを代入します。
byte* pdb = ( byte* )&d;
// byte型ポインタからiバイト分だけオフセットして、byte型の値を取得します。
byte[] db = new byte[16];
for( int i = 0; i < 16; i++ ) db[i] = *( pdb + i );
Console.WriteLine( "メモリ上での並び順 : {0}", string.Join( " ", db.Select( _ => _.ToString( "X2" ) ) ) );
}
}
※アンセーフコードを扱うので、コンパイル時に「/unsafe」オプションを付けます。
◆ 実行結果
※使用したコンピューターのCPUのバイトオーダーはリトルエンディアン方式です。
元の値 : -0.4972397250606885993375668763
内部表現の値 : 801C0000 10111213 14151617 18191A1B
メモリ上での並び順 : 00 00 1C 80 13 12 11 10 1B 1A 19 18 17 16 15 14
2. decimal型の数値における、メモリ上での並び方
実行結果にあるdecimal型の数値の内部表現とメモリ上での並び順を見比べると、内部表現の値を4バイトずつ分割し、各要素の中はバイト単位で逆順に並んでいることが分かります。
しかし、4バイトずつ分割したものについて、内部表現での並び順を上位から3→2→1→0(※GetBitsメソッドで取得した時の要素のインデックスに合わせています)とすると、メモリ上では3→2→0→1となっています。
decimal型の謎は深い・・・
それでは、See you next!