Open2

unsafe struct操作関連

blkcatmanblkcatman

C#で固定長配列を使う場合のアレコレ

以下のような配列を考える場合、いろいろな方法がとれる。

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit, Pack = 2)]
public unsafe struct TestStruct
{
    [FieldOffset(0)] private fixed byte Sign[4];
    ...
}

SpanのCopyToを使ってコピー

明示的に配列からコピーしたいときに使えそうだが、関数を抜けるまでstackに配列が積まれるので注意。また、長めの配列じゃない限りは効率が良くなさそう。コピー先の配列の長さが不足している場合は例外を吐くので比較的安全

ReadOnlySpan<byte> source = stackalloc byte[] {0xFF, 0xFF, 0xFF, 0xFF};
Span<byte> dest = new Span<byte>(Unsafe.AsPointer(ref Sign[0]), 4);
source.CopyTo(dest);

他の型にキャストして直接値書き換え(Unsafe.Add使用)

配列の先頭の参照情報を使って別の型の参照型に強制的にキャスト。短い配列の時は効率は良さそうだが、エラーも例外もなしに参照範囲外もアクセスできるので大変危険。エンディアンの問題がある

ref var dest = ref Unsafe.As<byte, ushort>(ref Sign[0]);
Unsafe.Add(ref dest, 0) = 0xFFFF
Unsafe.Add(ref dest, 1) = 0xFFFF

他の型にキャストして直接値書き換え(Unsafe.Add未使用)

こちらは↑の方法の型をuintにして、直接参照先を書き換える方法。エンディアンの問題がある

ref var dest = ref Unsafe.As<byte, uint>(ref Sign[0]);
dest = 0xFFFFFFFF
blkcatmanblkcatman

配列の比較方法など

ReadOnlySpan<T>.SequenceEqual()を使う

同じ型のSpan同士(特にbyte)であればSequenceEqualが効率が良さそう

source.SequenceEqual(dest)

他のプリミティブ型(または参照型)にキャストして比較する

source == dest