2015/04/13 Mon マーシャル
■[C#] 構造体からバイト配列を出力できたらどれだけ楽だろうか
対象
検証
Marshal.AllocHGlobal + Marshal.StructureToPtr/PtrToStructure
下記のような定義があるとする。
[StructLayout(LayoutKind.Sequential)] struct TestStructure { public byte param1; [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)] public byte[] array1; public int param2; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public int[] array2; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] public string param3; [MarshalAs(UnmanagedType.Struct)] public TestStructureInternal param4; } [StructLayout(LayoutKind.Sequential)] struct TestStructureInternal { public int next; public char chr; } public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { var item = new TestStructure(); //01 item.param1 = (byte)1; //0a 0b 0c item.array1 = new byte[] {0x0a,0x0b,0x0c}; //02 00 00 00 item.param2 = (int)2; //ff 00 00 00 00 01 00 00 item.array2 = new int[] { 0x00ff, 0x0100 }; //74 65 73 00 tes. ←MarshalAsでSizeConstに4を指定している関係でNull終端が設定されたためtが欠落しているものと思われる.ByValTStrの指定が悪いのか原因不明。 item.param3 = "test"; item.param4 = new TestStructureInternal(); //06 00 00 00 item.param4.next = (int)6; //61 item.param4.chr = 'a'; //00 00 00 ←おそらくバウンダリのための空白 string filename = "outfile.out"; if (File.Exists(filename)) { File.Delete(filename); } using (var file = new FileStream(filename, FileMode.CreateNew)) using (var writer = new BinaryWriter(file)) { ReadWriteStructWithAllocHGlobal.WriteTo(writer, item); } } }
実行結果は以下のようになった。わかりやすいように上記コードにもダンプを貼り付けておく。
00000000 01 0a 0b 0c 02 00 00 00 ff 00 00 00 00 01 00 00 |................| 00000010 74 65 73 00 06 00 00 00 61 00 00 00 |tes.....a...|
解決策
このままでは実装しても使い物にならない(文字列の終端NULLが勝手に挿入される)ので、カスタマイズで実装してみた。
https://gist.github.com/indication/6b8d85c7da8cf6fd8f5c#file-readwritestructwithreflection-cs
Structure→byte[]はできたが、逆はまだ実装できていない。
BigEndianにも対応してみたが、「BitConverter.IsLittleEndian」のフラグを参照していないので、考慮に入れてみる。
isBigEndian=falseの場合の結果 00000000 01 0a 0b 0c 02 00 00 00 ff 00 00 00 00 01 00 00 |................| 00000010 74 65 73 74 06 00 00 00 61 00 |test....a.| isBigEndian=trueの場合の結果 00000000 01 0a 0b 0c 00 00 00 02 00 00 00 ff 00 00 01 00 |................| 00000010 74 65 73 74 00 00 00 06 00 61 |test.....a|
ライセンス
上記検証コードについては、BinaryReader・BinaryWriterでの構造体の読み書き (構造体⇔バイト配列の変換) - Programming/.NET Framework/Tips - 総武ソフトウェア推進所 の規約に基づくものとし、私が記載したものはWTFPL Version 2.0とします。
参考文献
- BinaryReader・BinaryWriterでの構造体の読み書き (構造体⇔バイト配列の変換) - Programming/.NET Framework/Tips - 総武ソフトウェア推進所 複数の処理サンプル(完全)
- 構造体からポインタ(バイト配列)への変換 - schima.hatenablog.com 処理速度の比較等
- Marshal.StructureToPtr
- CopyMemory
- ポインタ
- C#で構造体と配列のコピーについて(ビッグエンディアンと、リトルエンディアン)
- BitConverter.IsLittleEndianフィールド
- IPAddress.NetworkToHostOrder メソッド
- IPAddress.HostToNetworkOrderメソッド
- 38 https://www.google.co.jp/
- 12 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=12&cad=rja&uact=8&ved=0CCIQFjABOAo&url=http://d.hatena.ne.jp/indication/20150413/1428941895&ei=4bReVaa8NMe58gX-hIOwBQ&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g&bvm=bv.93990622,d.dGc
- 12 https://www.google.co.jp
- 6 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=5&ved=0CDoQFjAEahUKEwjRucbJyPDGAhUC4KYKHdiqAEE&url=http://d.hatena.ne.jp/indication/20150413/1428941895&ei=1oGwVdH2N4LAmwXY1YKIBA&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g&bvm=b
- 5 http://www.google.co.jp/url?url=http://d.hatena.ne.jp/indication/20150413/1428941895&rct=j&frm=1&q=&esrc=s&sa=U&ei=wRmeVc6NPIewmAWz36eIDA&ved=0CEAQFjAGOAo&usg=AFQjCNH-ARmY_trZJhHHeRwEhMha4sD1Kw
- 4 http://search.yahoo.co.jp/search?p=C#+構造体+BinaryWriter&aq=-1&oq=&ei=UTF-8&fr=top_ga1_sa&x=wrt
- 4 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0CC8QFjAC&url=http://d.hatena.ne.jp/indication/20150413/1428941895&ei=twlkVdPvHoWc8QX7r4DoCA&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g&bvm=bv.93990622,d.dGc&cad=rjt
- 4 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=9&ved=0CFkQFjAIahUKEwj7183en4TGAhVCBZIKHYIfAN0&url=http://d.hatena.ne.jp/indication/20150413/1428941895&ei=gbd3VbuTHcKKyASCv4DoDQ&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g&bvm=bv.9503
- 3 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&ved=0CEMQFjAF&url=http://d.hatena.ne.jp/indication/20150413/1428941895&ei=cbtaVdWsL4358QXJjoD4Ag&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g&sig2=mEyaGbP8Gf6V4KD1WzTSLQ
- 3 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=8&ved=0CFcQFjAHahUKEwjW_sKqsoTIAhWIlZQKHQo1DY4&url=http://d.hatena.ne.jp/indication/20150413/1428941895&usg=AFQjCNFu0GtY2AjFcf7J9Qkxr5B_OFVR6g