あなたがいる限り、すべてのフィールドは、blittable型であるため、メモリ内の構造体のフィールドの順序を見つけるために反射または任意の他のメカニズムを使用する必要はありませんblittable型のタイプとLayoutKind.Sequential
を使用している場合これは不要です。
LayoutKind.Sequential
で宣言された構造体のblittableフィールドは、フィールドが宣言されている順番でメモリに格納されます。これは、LayoutKind.Sequential
の意味です!
From this documentation
:
blittable型タイプの場合は、LayoutKind.Sequentialは、マネージメモリ内のレイアウトとアンマネージメモリ内のレイアウトの両方を制御します。非blittable型の場合は、クラスまたは構造体がアンマネージコードにマーシャリングされ、マネージメモリのレイアウトは制御されません。
各フィールドの埋め込み量はわかりません。それを見つけるには、以下を参照してください。 LayoutKind.Auto
を使用するときに、フィールドの順序を決定するために
、あるいはフィールド・オフセット任意のレイアウト
を使用するときにそれはあなたが危険なコードを使用して満足している場合は、構造体のフィールドオフセットを見つけるのは比較的簡単だし、にありません反射を使用します。
構造体の各フィールドのアドレスを取得し、構造体の先頭からオフセットを計算するだけです。各フィールドのオフセットを知ることで、順序(およびそれらの間のパディングバイト)を計算できます。最後のフィールドに使用されているパディングバイトを計算するには、sizeof(StructType)
を使用して構造体の合計サイズを取得する必要もあります。
次の例は、32ビットと64ビットで動作します。構造体が既に固定されているので、あなたが原因それがスタック上にあることにfixed
キーワードを使用する必要はないことに注意してください(あなたがそれをfixed
を使用しようとすると、コンパイルエラーが発生します):
using System;
using System.Runtime.InteropServices;
namespace Demo
{
[StructLayout(LayoutKind.Auto, Pack = 1)]
public struct TestStruct
{
public int I;
public double D;
public short S;
public byte B;
public long L;
}
class Program
{
void run()
{
var t = new TestStruct();
unsafe
{
IntPtr p = new IntPtr(&t);
IntPtr pI = new IntPtr(&t.I);
IntPtr pD = new IntPtr(&t.D);
IntPtr pS = new IntPtr(&t.S);
IntPtr pB = new IntPtr(&t.B);
IntPtr pL = new IntPtr(&t.L);
Console.WriteLine("I offset = " + ptrDiff(p, pI));
Console.WriteLine("D offset = " + ptrDiff(p, pD));
Console.WriteLine("S offset = " + ptrDiff(p, pS));
Console.WriteLine("B offset = " + ptrDiff(p, pB));
Console.WriteLine("L offset = " + ptrDiff(p, pL));
Console.WriteLine("Total struct size = " + sizeof(TestStruct));
}
}
long ptrDiff(IntPtr p1, IntPtr p2)
{
return p2.ToInt64() - p1.ToInt64();
}
static void Main()
{
new Program().run();
}
}
}
LayoutKind.Sequential
を使用している場合、フィールド・オフセットを決定するためにあなたの構造体にはLayoutKind.Sequential
、あなたが直接オフセットを取得するMarshal.OffsetOf()
を使用することができますを使用していますが、これはLayoutKind.Auto
とない仕事ない場合:
を
foreach (var field in typeof(TestStruct).GetFields())
{
var offset = Marshal.OffsetOf(typeof (TestStruct), field.Name);
Console.WriteLine("Offset of " + field.Name + " = " + offset);
}
LayoutKind.Sequential
を使用している場合は、unsafe
コードを必要としないため、これは明らかに良い方法です。これははるかに短く、事前にフィールドの名前を知る必要はありません。上で述べたように、メモリ内のフィールドの順序を決定する必要はありませんが、どれだけのパディングが使用されているかを知る必要がある場合には便利です。
これらの属性に反映することで解決できませんか? –
@newStackExchangeInstanceどの属性ですか? –
'LayoutKind.Sequential'は、blittable型だけが構造体に存在する場合にのみ、管理された表現を制御します。区切り不可能な型がある場合、フィールドの順序は実行時に制御されます。例えば。 http://stackoverflow.com/q/14024483/11683を参照してください。 – GSerg