2010-01-09 2 views
1

P/Invoke를 통해 관리되지 않는 라이브러리로 작업하고 있으며 구조체가 모두 동일한 기본 레이아웃을 사용하므로 하나만 게시합니다.관리되는 구조체와 관리되지 않는 구조체가 같은 크기가 아닙니다.

struct Agraph_t { 
    int tag:4; 
    int kind:4; 
    int handle:24; 
    char **attr; 
    char *didset; 
    char *name; 
    Agdata_t *univ; 
    Dict_t *nodes, *inedges, *outedges; 
    Agraph_t *root; 
    Agnode_t *meta_node; 
    Agproto_t *proto; 
    Agraphinfo_t u; 
}; 

내 래퍼가 이러한 개체를 사용하는 방식 때문에 Agraph_t 내부의 구조체를 IntPtr으로 참조해야합니다. 비트 필드의 값에 쉽게 액세스 할 수 있도록하는 속성을 추가했습니다.

public struct Agraph_t { 
    public uint tag_kind_handle; 
    public IntPtr attr; 
    public string didset; 
    public string name; 
    public IntPtr univ; 
    public IntPtr nodes, inedges, outedges; 
    public IntPtr root; 
    public IntPtr meta_node; 
    public IntPtr proto; 
    public IntPtr u; 

    public uint Tag { 
     get { return (tag_kind_handle & 15u); } 
    } 

    public uint Kind { 
     get { return (tag_kind_handle & 240u)/16; } 
    } 

    public uint Handle { 
     get { return (tag_kind_handle & 4294967040u)/256; } 
    } 
} 

아무 것도 작업하기 전에 각 구조체의 크기를 지정하여 관리되지 않는 라이브러리를 초기화해야합니다.

aginitlib(Marshal.SizeOf(typeof(Agraph_t)), ..., ...); 

이렇게하면 오류가 발생하지 않으며 라이브러리를 잘 사용할 수 있습니다. 그러나 라이브러리의 일부는 자체 관리되지 않는 구조체의 크기를 사용하여 aginitlib을 호출합니다. 이 시점에서 라이브러리는 두 개의 서로 다른 크기로 초기화되었다는 경고를 받으면서 불안정하게 만듭니다 (특정 작업 후 AccessViolationException 초 발생).

추가 된 속성이 구조체의 크기에 포함되며 관리되지 않는 버전보다 커야합니까? 나는 그들을 제거하고 어떤 일이 일어나는지 보 겠지만, 내 코드는 그것들에 크게 의존하기 때문에 그것을 어렵게 만든다.

Size 속성과 함께 StructLayoutAttribute을 사용해야합니까? 그것에 대해 나를 혼란스럽게하는 유일한 것은 IntPtr입니다. 라이브러리는 엄격하게 32 비트이므로 계속해서 안전하게 해당 필드가 32 비트라고 가정 할 수 있습니까?

답변

1

차이점은 u에 대한 선언 때문입니다. 관리되지 않는 선언이 있습니다

Agraphinfo_t u; 

이는 Agraphinfo_t가 Agraph_t 구조체에서 인라인 할당된다는 것을 의미한다. Agraphinfo_t가 16 바이트 크기라면, sizeof (Agraph_t)에 16 바이트를 기여합니다.

그러나, 관리되는 선언에서,이 같은 U를 선언

public IntPtr u; 

이것은 포인터이 Agraph_t 구조체에 할당되는 것을 의미한다. 32 비트 시스템에서는 sizeof (Agraph_t)에 4 바이트를 기여합니다. 따라서 Agraph_t에 대해 계산 된 두 크기는 동기화되지 않습니다.

이 문제를 해결 Agraphinfo_t에 동일한 기능의 관리를 선언하고 Agraph_t에서 해당 인스턴스 만들려면 : 그들은의 크기에 영향을 미칠 것이기 때문에

public struct Agraphinfo_t 
{ 
    // fields go here as per unmanaged definition 
} 

public struct Agraph_t 
{ 
    // .... 
    public Agraphinfo_t u; 
} 
+0

아, 알겠습니다. 나는 실종 된'*'을 알아 차리지 못했다. 이 솔루션의 문제점은'Agraphinfo_t' 구조체가 (필드의 수면에서) MASSIVE이고 라이브러리가 컴파일 된 방법에 따라 다른 필드를 사용한다는 것입니다. 어떤 컴파일러 플래그를 사용했는지 알지 못하기 때문에 포함 할 필드가 확실하지 않습니다. 어떤 팁? –

+0

불행히도 아닙니다. 크기를 맞추려면, 관리되지 않는'Agraphinfo_t' 구조체와 같은 크기의 크기 (구조체 내)를 차지하는 슬롯에 * something *을 제공해야합니다. 바이트 배열을 사용하여 참조가 아닌 인라인 공간으로 취급되도록 적절한 마샬링 플래그를 사용할 수도 있지만 크기를 계산해야합니다. sizeof (Agraphinfo_t)를 인쇄하는 작은 C 프로그램. 그래도 약속은 안돼 - 미안해! – itowlson

+0

그게 가능합니다. 그 동안, 나는 aginitlib에 대한 자체 호출을하는 라이브러리 부분이 다른 것들보다 먼저 호출되어야하고 관리되는 래퍼에서 수동으로 호출하는 기능을 제거해야한다는 요구 사항을 추가했다. 작동하지만 꼭 지키고 싶은 것은 아닙니다. –

1

IntPtr은 32 비트 코드에서 4 바이트이며 64 비트 모드에서는 8 바이트 길이입니다.

현재 런타임에 대한 값의 크기를보고하는 IntPtr.Size 속성을 사용하여 크기를 결정할 수 있습니다.

다른 질문에 대해서는 동일한 패딩 및 필드 크기로 관리되는 구조와 관리되지 않는 구조가 동일한 방식으로 메모리에 배치되도록 실제로 StructLayoutAttribute을 사용해야합니다.

메모리의 구조체 크기에 영향을주기 때문에 구조체에서 속성을 제거해야합니다.

+0

는 "당신은 또한 구조체에서 속성을 제거해야합니다을 기억에있는 구조. " 이것은 정확하지 않습니다. 속성은 인스턴스가 아닌 메타 데이터이며 유형 * 당 공간 *을 차지합니다. (속성에 자체 배킹 필드가있는 경우 귀하의 의견은 사실이지만 그렇지 않은 것은 tag_kind_handle 필드를 통한 getter 메서드입니다.) – itowlson

관련 문제