2016-08-31 9 views
0

C#에서는 bool 유형의 16 개 변수가 포함 된 여러 개의 다른 구조체를 생성합니다. 이 구조체 중 몇 가지를 다른 구조체와 결합하여 다른 데이터 형식과 결합 할 것입니다. 길이가 2 바이트 인 것으로 처리해야합니다. I는 그것이 비록 0, 1 또는 2C# StructLayout Pack = ?? bool 값과 함께 사용하기

[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; 
} 
+0

패킹/레이아웃은 바이트 단위로 수행됩니다. 즉, 부울은 순전히 패킹에 의존하는 1 바이트 미만을 차지하지 않습니다. 두 개의 전용 바이트 필드와 해당 바이트 내 적절한 비트를 참조하는 여러 속성을 사용하는 것과 같이 좀 더 복잡한 작업을 수행해야합니다. –

+0

[BitVector32] (https://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32.aspx)를 사용하여 32 비트로 줄일 수 있습니다. 또는, http://stackoverflow.com/questions/4107039/bitarray-alternative-for-the-net-micro-framework/4107287#에 설명 된 기술을 사용할 수 있지만'long'보다는'ushort'를 사용하십시오. –

답변

0

팩 값으로 생성되었는지 여부에 관계없이 Marshal.SizeOf 할 때 아래 코드 입력 CtrlWord1의 생성 변수 (64)의 길이를 제공한다 C#의 bool 형식의 크기가 1 바이트 (sizeof(bool) == 1) 인 경우 CLR은 기본값으로 관리되지 않는 BOOL 형식으로 마샬링합니다. 이것은 Marshal.SizeOf에 전화 할 때 얻는 크기입니다.

BOOL은 크기가 4 바이트 인 int에 대한 Windows SDK 헤더의 typedef입니다. 왜? 이 헤더는 C 언어 용으로 작성 되었기 때문에이 언어에는 1 급 부울 유형이 없었습니다. 이제는 가능하지만, 하위 호환성을 위해 의사 결정이 수정되었습니다. CLR은 bool 형식을이 방법으로 BOOL 값을 사용하는 Windows API 함수와 호환되도록 마샬링합니다. Windows API와의 interop이 P/Invoke의 가장 일반적인 사용이기 때문에 CLR은이 값을 사용하여이 값을 사용합니다. (P/Invoke 시그니처에 대한 기본 호출 규칙이 cdecl 대신 stdcall 인 것과 같은 이유입니다.)

bool을 4 바이트 BOOL이 아닌 1 바이트 bool로 처리하도록 CLR에 알려려면 MarshalAs attribute. 안타깝게도 다음과 같이 16 번 사용해야합니다.

[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 유형을 사용하십시오.

+1

그것은 그에게 16 바이트 구조체를 줄 것이고, 그는 2 바이트 비트 필드를 찾고 있습니다. –

+0

'BitArray '의 문제점은 할당 오버 헤드 (12 또는 24 바이트)와 20 또는 30 바이트의 배열 오버 헤드를 발생시키는 배열을 할당한다는 것입니다. –

0

Glorin Oakenfoot said it much better than I could , 그래서 난 그냥 그에게

포장/레이아웃을 인용 것은 바이트 수준에서 이루어집니다. 즉, 부울은 순전히 패킹에 의존하는 1 바이트 미만을 차지하지 않습니다. 두 개의 전용 바이트 필드와 해당 바이트 내 적절한 비트를 참조하는 여러 속성을 사용하는 것과 같이 좀 더 복잡한 작업을 수행해야합니다.

여기서 각 항목은 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 
}