0

C# では、bool 型の 16 個の変数を含む複数の異なる構造体を作成しています。これらの構造体をいくつか用意し、他のデータ型と組み合わせてより複雑な構造体にします。長さ 2 バイトとして扱う必要があります。以下のコードでは、タイプ CtrlWord1 で作成された変数は、Pack 値が 0、1、2 のいずれで作成されたかに関係なく、Marshal.SizeOf を実行すると長さが 64 になります。

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    public bool a1;
    public bool a2;
    public bool a3;
    public bool a4;
    public bool a5;
    public bool a6;
    public bool a7;
    public bool a8;
    public bool b1;
    public bool b2;
    public bool b3;
    public bool b4;
    public bool c1;
    public bool c2;
    public bool c3;
    public bool c4;
}
4

2 に答える 2

2

C#のbool型はサイズが 1 バイトしかありませんが ( sizeof(bool) == 1)、CLR は既定でそれをアンマネージBOOL型としてマーシャリングします。これは、 を呼び出したときに得られるサイズですMarshal.SizeOf

BOOLintサイズが 4 バイトの の Windows SDK ヘッダーの typedefです。なんで?これらのヘッダーは C 言語用に作成されたものであり、この言語には最初のクラスのブール型がありませんでした。現在はそうしていますが、後方互換性の理由から決定は固定されています。Windows API との相互運用性は P/Invoke の最も一般的な使用法であるため、値boolを使用する Windows API 関数との互換性を保つために、CLR はこのように型をマーシャリングします。BOOL(P/Invoke 署名の既定の呼び出し規則が cdecl ではなく stdcall であるのと同じ理由です。)

boolを4 バイトではなく 1 バイトの bool として扱うように CLR に指示するには、属性BOOLを使用します。残念ながら、16 回使用する必要があります。MarshalAs

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    [MarshalAs(UnmanagedType.I1)]  // marshal as a 1-byte signed int, not a 4-byte BOOL
    public bool a1;

    // etc.
}

これにより、構造体がわずか 16 バイトになることが保証されます。

ただし、ビットフィールドを生成する魔法の属性はありません。Int32タイプを使用して、これを自分で作成および管理する必要があります。またはBitArrayタイプを使用してください。

于 2016-08-31T14:05:47.400 に答える
0

グローリン オーケンフット の 言葉 は 私 より ずっと 上手 だった .

パッキング/レイアウトはバイト レベルで行われます。これは、純粋にパッキングに依存することで、bool が 1 バイト未満になることは決してないことを意味します。2 つのプライベート バイト フィールドと、それらのバイト内の適切なビットを参照する複数のプロパティを使用するなど、もう少し複雑なことを行う必要があります。

これはその実装で、各項目の右側をインクリメント1 << _して次のビット フィールドに移動します。

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    private Int16 _backingField;

    private void SetBitfield(Int16 mask, bool value)
    {
        if (value)
        {
            _backingField = (Int16)(_backingField | mask);
        }
        else
        {
            _backingField = (Int16)(_backingField & ~mask);
        }
    }

    private bool GetBitfield(Int16 mask)
    {
        return (_backingField & A1_MASK) != 0;
    }

    private const Int16 A1_MASK = 1 << 0;
    public bool a1
    {
        get { return GetBitfield(A1_MASK); }
        set { SetBitfield(A1_MASK, value); }
    }


    private const Int16 A2_MASK = 1 << 1;
    public bool a2
    {
        get { return GetBitfield(A2_MASK); }
        set { SetBitfield(A2_MASK, value); }
    }

    private const Int16 A3_MASK = 1 << 2;
    public bool a3
    {
        get { return GetBitfield(A3_MASK); }
        set { SetBitfield(A3_MASK, value); }
    }

    private const Int16 A4_MASK = 1 << 3;
    public bool a4
    {
        get { return GetBitfield(A4_MASK); }
        set { SetBitfield(A4_MASK, value); }
    }

    //And so on
}
于 2016-08-31T14:22:26.293 に答える