byte[] を構造体に、またはその逆にコピーする方法をいくつか見てきました。ただし、byte[]ポインターを構造体にキャストできるかどうかは疑問でした(Cで行うように)。
byte[] を構造体にキャストし、構造体に変更を加えて、変更が自動的に byte[] に表示されるようにしたいと考えています。
ありがとう、レザ
void*
ポインタをキャストするだけです(途中で経由する必要がある場合もあります):
struct Foo
{
public int Bar;
}
static unsafe void Main()
{
byte[] buffer = new byte[10];
fixed (byte* untyped = buffer)
{
var typed = (Foo*)untyped;
typed[0].Bar = 123;
}
// buffer has the changes
}
バッファにオフセットする必要がある場合は、 を使用しますbyte* untyped = &buffer[offset]
。
生の構造体ポインターが必要な場合は、次のようにします。
fixed (byte* ptr = buffer)
{
var typed = (Foo*)ptr;
Foo* foo = &typed[0];
foo->Bar = 123;
}
ただし、またはFoo*
を期待するメソッドにa を渡すことはできないことに注意してください。Foo
ref Foo
このアプローチは、私が望んでいたことを達成するための最も簡単な方法であることがわかりました。バイト [] が要素とオーバーラップするように構造体を定義すると、コピーは構造体とバイト [] の間で効果的に透過的になります (エンディアンがあなたのものであると仮定します)期待;私の場合はそうです)。
[StructLayout(LayoutKind.Explicit)]
public unsafe struct ListEntry {
[System.Runtime.InteropServices.FieldOffset(0)] public fixed byte raw[512];
[System.Runtime.InteropServices.FieldOffset(0)] public byte version;
[System.Runtime.InteropServices.FieldOffset(1)] public UInt16 magic;
[System.Runtime.InteropServices.FieldOffset(3)] public UInt32 start_time;
[System.Runtime.InteropServices.FieldOffset(7)] public UInt16 run_id;
[System.Runtime.InteropServices.FieldOffset(9)] public UInt16 channels;
[System.Runtime.InteropServices.FieldOffset(11)] public UInt16 sampling_rate;
[System.Runtime.InteropServices.FieldOffset(13)] public UInt32 start_sector;
[System.Runtime.InteropServices.FieldOffset(510)] public UInt16 checksum;
}
速度が重要でない場合、最善の策は、おそらくデータを に格納し、byte[]
それへの不変の参照を保持し、byte[]
get/set メソッドが配列にアクセスするプロパティを持つクラスを持つことです。配列自体がオブジェクトの状態を保持するため、プロパティの取得/設定は常に反映され、配列の状態に反映されます。「安全でない」コードは必要ありません。
メソッドはおそらく次のようになります。
public static class IntPack
{ // All methods ssume unchecked arithmetic
public static Int16 FetchI16LE(this byte[] dat, int offset)
{
return (Int16)(dat[offset] + (dat[offset + 1] << 8));
}
public static Int32 FetchI32LE(this byte[] dat, int offset)
{
return dat[offset] + (dat[offset + 1] << 8) +
(dat[offset + 2] << 16) + (dat[offset + 3] << 24);
}
public static void StuffI16LE(this byte[] dat, int offset, int value)
{
dat[offset] = (byte)(value);
dat[offset+1] = (byte)(value >> 8);
}
public static void StuffI32LE(this byte[] dat, int offset, int value)
{
dat[offset] = (byte)(value);
dat[offset + 1] = (byte)(value >> 8);
dat[offset + 2] = (byte)(value >> 16);
dat[offset + 3] = (byte)(value >> 24);
}
}
示されているメソッドは、リトル エンディアンの順序付けを前提としています。ビッグエンディアンに対応する __BE メソッド メソッドを簡単に作成できます。