schwarzの雑記 このページをアンテナに追加 RSSフィード

07/06/05 (Tue)6月5日の雑記

[] 6月5日の雑記 - schwarzの雑記 を含むブックマーク

先日の構造体の話で出てきたFieldOffsetですが、あれを使えばCの共用体相当のものが作れるのではなかろうかと思いまして、実際できました。

[StructLayout(LayoutKind.Explicit)]
struct MyUnion {
    [FieldOffset(0)]
    public int hoge;
    [FieldOffset(0)]
    public int fuga;
}

という様に、どちらのオフセットも同じにしてやればよいのです。

MyUnion union = new MyUnion();
union.hoge = 1;

Console.WriteLine(union.fuga);

この結果は、驚く無かれ、1です。



といっても共用体なんてCの入門書でチラッと見て以来ご無沙汰もいいところですが、QueryPerformanceなんたらを調べているときにLARGE_INTEGERの定義を見て、共用体ってこうやって使うのかとかなり感動した覚えがあるので、以下ではC#で似たようなものを作ってみます。


構造体はこんな感じで定義します。4バイトの正の整数を表すものです。

[StructLayout(LayoutKind.Explicit)]
struct MyUInt {
    [FieldOffset(0)]
    public uint all;
    [FieldOffset(0)]
    public ushort lower;
    [FieldOffset(2)]
    public ushort higher;
}

allが全体としての4バイトの値を持っていて、lowerがその下位2バイト、higherが上位2バイトをあらわします。使ってみましょう。

MyUInt mu = new MyUInt();

mu.lower = 1;
Console.WriteLine(mu.all);  // 1

mu.higher = 1;
Console.WriteLine(mu.all); // 65537  (= 65536 + 1 = 0xFFFF + 0x0001)

mu.all = 65540;
Console.WriteLine("higher:{0} lower:{1}", mu.higher, mu.lower);
// higher:1 lower:4

ちょっとわかりにくいかもしれませんが、なかなか良くできてます。10進だとわかりにくいので16進で書くと、

 FFFF     FFFF
higher   lower

という感じで、上4桁がhigherに入ってて下4桁がlowerに入っています。そしてその2つがまとめてallに入っています。



さて多少話はそれますが、先日書いたimplicitはこういう構造体を作るときにすごく役立ちます。というのは、ある値で初期化したいとき、上記のようにいちいちnewでつくってからそのあとallに代入なんて、かったるいのもいいところです。そこで、構造体の中にこんなメソッドを用意します。

static public implicit operator MyUInt(uint u) {
    MyUInt mu = new MyUInt();
    mu.all = u;
    return mu;
}

これで、

MyUInt mu = 123456;

と一発で代入できます。すばらしい。

この調子でToStringとかも再定義して、allは完全に隠蔽してしまったほうがいいでしょう。

こんたろうこんたろう2007/06/06 03:47C#は触っていないのでschwarzの雑記が日々わからなくなっていく今日この頃…。たまにはRubyネタも入れてください。

僕が共用体を面白いと思ったのはH8マイコンを触った時です。HEWの吐き出すヘッダでは、1bitのビットフィールドを8つメンバに持つ構造体とcharの共用体を使っていて、PADR.BYTEやPADR.BIT.B0のようにレジスタをアクセスできるようになっていました。schwarzさんも講義でお世話になったはずです。

このPADRとかも実体は#define (*(resister_union*)0x01234567)のようなアドレスを直接指定したマクロになっていてマイコン楽しいなー、と思った記憶がありますが、それは別の話。

そんなわけでC#でもビットフィールドを作れないものかとちょっとだけ調べてみたのですが、言語としてはサポートしていないので微妙っぽいですね。個人的に共用体とビットフィールドはセットのように考えている節があるので、ちょっと残念。

SchwarzSchwarz2007/06/06 22:42あー、そう言われてみれば、あれ共用体ですね。すごく納得。

Ruby・・・ネタがさっぱり無いんですよね。というかRubyに限らずネタが無いんだけど、なんとか振り絞って書いてみますよ。