C#の共用体(Union)

.NET Core, .NET Framework, C#

C#には共用体を書くための文法が用意されていないけど、ちょっと工夫すれば共用体とまったく同じ性質のものがつくれる。

例えば、次のような共用体が必要になったとしよう。

この共用体では、符号なし32ビット整数と、4つのbyte型整数の並びが同じ開始アドレスになるものとする。

C/C++的に書くなら次のような感じだ。

これをC#でも実現したい。

名前空間 System.Runtime.InteropServices の機能を使うと、構造体の各メンバの開始アドレスを個別に調節できるので、この性質を使う。

ポイントは次の2点。

  • 構造体にStructLayoutAttributeクラスを付加し、引数でLayoutKind.Explicit(すべてのメンバの開始アドレスを個別に指定する)を指定する。
  • 構造体の各メンバにFieldOffsetAttributeクラスを付加し、引数で開始アドレスのオフセット(構造体の最初から何バイト目を開始にするか)を指定する。

コード例は次のような感じ。

こうしてつくった"共用体"は、次のようにして利用できる。何の変哲もない共用体になっている。

byte1~byte4の数値の並びが1,2,3,4ではなく逆順になっていることに違和感を覚える人もいると思うけど、これは私のPCのCPUがx86アーキテクチャであることによる。

リトルエンディアンの場合

x86アーキテクチャは数値をリトルエンディアンで扱うため、uint型の数値はメモリ上で上図のような並びで存在する。

ビッグエンディアンなど、別の並びで扱うアーキテクチャで同じことをやろうとすると結果が変わるはずなので注意。