2012-06-21 2 views
3

복잡한 데이터 구조를받는 UDP 클라이언트를 작성하고 있습니다. C++로 구조체를 가지고 있지만 내 프로그램은 C#으로되어 있습니다.C++에서 C++로 구조체를 이전하는 방법

Bitfiels 및 공용체에는 많은 구조가 있습니다.

구조체를 손으로 변환 할 필요가없는 방법이 있습니까?

또한 C#에서 Bitfields 및 Union을 구현하는 쉬운 방법이 있습니까?

지금은 Bitfields의 등록 정보를 사용하고 있지만 실수가있을 가능성이있는 어려운 작업입니다.

제가 지금하고있는 간단한 예제를 제공했습니다. 약 100 줄의 코드가있는 약 50 개의 구조체가 있습니다.

예 : C++ :

typedef struct Message_s 
{ 
    unsigned char var : 2; 
    unsigned char var2 : 6; 

    union 
    { 
     struct 
     { 
      unsigned char sVar; 
      unsigned char sVar2; 
     } 
     char arr[32]; 
    }  
}Message_t; 

예 C 번호 :

는 짧은 대답이 '아니오'
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] 
struct Message_s 
{ 
    private byte Field1 
    public byte var 
    { 
     get 
     { 
      return (byte)(Field1 & 0x03); 
     } 
     set 
     { 
      Field1 = (byte)((Field1 & ~0x03) | value); 
     } 
    public byte var2 
    { 
     get 
     { 
      return (byte)(Field1 & 0xFC); 
     } 
     set 
     { 
      Field1 = (byte)((Field1 & 0x03) | value<<2); 
     } 
    } 
//unions may be possible with properties... 
} 
+0

비트 필드 조작에 관해서는 System.Collections.Specialized.BitVector32를 참조하십시오. 또한 수행중인 작업에 따라 적절한 너비의 열거 형을 사용하여 Flags 특성으로 꾸미기를 원할 수 있습니다. – JamieSee

+0

ok 이것에 대해 : 모든 구조체를 조작하는 manged C++ DLL을 작성하면 C#에서 액세스 할 수 있습니다. 그렇습니까? 또 다른 질문은 C++ 컴파일러가 구조체의 바이트와 비트 순서를 유지합니까? –

+0

불행히도, @ChristianElsner, 나는 똑같은 생각을 가지고 있었고 이것은 효과가없는 것 같습니다. 이러한 종류의 구조체는 컴파일되지만 멤버는 C#에서 액세스 할 수 없습니다. 'struct '를'value class'로 바꾸면 관리되는 구조체가됩니다.하지만 비트 필드와 유니온 모두에 대해 컴파일러 오류가 발생합니다. – karaken12

답변

2

대안으로, 코드에서 관리되지 않는 C++ 유형을 사용하는 방법이지만 여전히 입력이 필요합니다. VS C++ 프로젝트에서 관리되지 않는 구조체를 만들 :

public ref struct Date_ms 
{ 
    AutoPtr<Date_s> data; 
    Date_ms() 
    { 
     data = new Date_s(); 
    } 

    property unsigned nWeekDay 
    { 
     unsigned get() { return data->nWeekDay; } 
     void set(unsigned value) { data->nWeekDay = value; } 
    } 
    property unsigned nMonthDay 
    { 
     unsigned get() { return data->nMonthDay; } 
     void set(unsigned value) { data->nMonthDay = value; } 
    } 
    property unsigned nMonth 
    { 
     unsigned get() { return data->nMonth; } 
     void set(unsigned value) { data->nMonth = value; } 
    } 
    property unsigned nYear 
    { 
     unsigned get() { return data->nYear; } 
     void set(unsigned value) { data->nYear = value; } 
    } 
    property unsigned bob 
    { 
     unsigned get() { return data->bob; } 
     void set(unsigned value) { data->bob = value; } 
    } 
}; 

이 할 수있는 몇 가지 복사 및 붙여 넣기가있다 :

struct Date_s 
{ 
    union 
    { 
     struct 
     { 
      unsigned nWeekDay : 3; // 0..7 (3 bits) 
      unsigned nMonthDay : 6; // 0..31 (6 bits) 
      unsigned   : 0; // Force alignment to next boundary. 
      unsigned nMonth : 5; // 0..12 (5 bits) 
      unsigned nYear  : 8; // 0..100 (8 bits) 
     }; 
     unsigned bob; 
    }; 
}; 

이제 우리는이 구조를 래핑하는 관리되는 형식을 만듭니다. 여기에 사용하는 외부 항목도 있습니다. Kerr의 AutoPtr입니다. 또한 이니셜 라이저 작동을 위해 AutoPtr 코드에 T* operator=(T* rhs) { return (m_ptr = rhs); } 행을 추가했습니다 (커의 게시물에 대한 주석에 제안 된대로).

는 이제 C# 코드에서이 새로운 구조를 사용할 수 있으며, 모든 것이 예상대로 작동합니다 :

var test = new Date_ms(); 
test.nMonth = 3; 
test.nMonthDay = 28; 
test.nYear = 98; 
Console.WriteLine("{0}, {1}, {2}", test.nMonth, test.nMonthDay, test.nYear); 
Console.WriteLine("{0}", test.bob); 

결과를 3, 28, 98224에.

BIG GIANT 경고

가 관리하고이 같은 관리되지 않는 코드는 커는 처음에 AutoPtr을 쓴 이유입니다, 위험 혼합은 (BTW, 자신의 주제에 blog post은 읽기 가치가있다). 이것은 나를 위해 작동하지만 메모리 누수가 발생하지 않을 것이라고 보장 할 수는 없습니다. 을 배포하기 전에 의도 한대로 작동하는지 확인하십시오.

4

, C#을 형식으로 C의 ++ 구조체를 얻는 쉬운 방법이있을 것 같지 않습니다. 그러나 C# 구조체에서 유니온을 수행하는 방법이 있습니다. 이것이 좋은 아이디어인지 또는 수업을 처음부터 시작하는 것이 더 나은지는 당신에게 달려 있습니다.

LayoutKind.Explicit 사용하는 C#을 구조체에 노동 조합을 얻고 FieldOffset 속성 :

[StructLayout(LayoutKind.Explicit)] 
struct StructTest 
{ 
    // A byte at the beginning of the struct. 
    [FieldOffset(0)] 
    public byte byte1; 

    // Another byte immediately after it. 
    [FieldOffset(1)] 
    public byte byte2; 

    // Now an integer which covers both. 
    [FieldOffset(0)] 
    public Int16 int1; 
} 

당신은 당신이 기대하는 방법이를 사용할 수 있습니다

 var foo = new StructTest(); 
     foo.byte1 = 3; 
     foo.byte2 = 6; 
     Console.WriteLine("{0}", foo.int1); 

     var bar = new StructTest(); 
     bar.int1 = 5050; 
     Console.WriteLine("{0}, {1}", bar.byte1, bar.byte2); 

1539186, 19 생산하고 있습니다.

이렇게하면 유니온 구조가되지만, 여전히 BitFields의 주된 문제는 해결되지 않습니다. 이것에 대한 합의가없는 것 같습니다 (물론, 이미 완료 한 것을 제외하고는, 예를 들어, [1] 참조). MarshalAs 특성을 사용하여 사용자 지정 BitField 클래스를 기본 구조체에 매핑 할 수는 있지만 해당 수준의 노력으로 사용자 지정 클래스를 계속 작성하는 것이 더 쉬울 수도 있습니다.

관련 문제