2012-05-05 9 views
3

중첩되지 않은 필드가 겹쳐진 것으로보고 된 구조체가 있습니다.레이아웃 빌드를 마샬링 .Explicit 구조가 릴리스 빌드에서 실패합니다.

[FieldOffset(8)] 
Int32 X; 

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 
[FieldOffset(12)] 
string Y; 

[FieldOffset(28)] 
int Z; 

보고 된 에러는 다음

유형 'XXX'을로드 할 수 ...는 물체 필드에서 잘못 정렬 또는 비 오브젝트 필드에 의해 중첩 (12) 오프셋을 포함한다.

릴리스 구성 (TRACE, DEBUG 플래그 및 안전하지 않은 코드가 활성화되어 있고 최적화가 해제되어 있음)에서만 발생합니다. 추측하면 어떻게됩니까?

UPD : 덕분에 @svick. x64 빌드가 마셜링에 필요한 것이 아니라는 것을 확인했습니다.

+0

StructLayout 특성에 문자 집합을 지정하고 있습니까? http://msdn.microsoft.com/ko-kr/library/system.runtime.interopservices.structlayoutattribute.charset.aspx에서와 같이?그렇지 않다면 구조 사이에 charsets의 이상한 교환이있을 수 있다고 생각합니다. 구조가 1 바이트 문자로만 이루어 지지만 넓은 문자로는 올바르지 않습니다. – tyranid

+0

'LayoutKind.Explicit' 대신'LayoutKind.Sequential'을 사용할 수 있고'FieldOffset '속성? 언제나 가능한 것은 아니지만이 경우에 가능하면 전체 문제를 피할 수 있습니다. – hvd

답변

4

첫 번째 릴리스 구성은 이와 관련이 없습니다. 플랫폼 대상 : x64로 설정하면이 예외가 발생하지만 x86으로 설정하면 정상적으로 작동합니다.

나는이 문제에 대한 이유가 FieldOffset가 관리되는 메모리 (문서가이 말을하지 않는 경우에도)에 struct의 레이아웃을 지정하는 데 사용된다는 점이다 생각 하지만 MarshalAs 관리 메모리에 사용되지 않습니다.

관리 메모리의 개체에는 오프셋 12의 참조가 포함되어 있습니다. 모든 참조는 .Net (32 비트 응용 프로그램에서는 4 바이트, 64 비트에서는 8 바이트)에 정렬되어야하므로 응용 프로그램을 64 비트로 실행하면 예외가 발생합니다.

그래서 문제는 필드를 겹친 것이 아니라 오류 메시지의 다른 부분입니다. 필드가 잘못 정렬되었습니다.

쉬운 해결 방법은 응용 프로그램을 x86으로 컴파일하는 것입니다. 그게 가능하지 않다면 어떻게 해결해야할지 모르겠다.

0

시스템의 데이터 필드의 기본 정렬은 8 바이트라고 생각합니다. Y에 대해 오프셋 16을 사용해야합니다.

5

@ svick의 정답에 주석을 달아 주면서 문제는 구조체 선언이 CLR이 해당 객체 할당을 원자 적으로 만든다는 어려운 약속을 위반한다는 것입니다. 64 비트 모드에서는 작동하지 않고 오프셋 12로 개체 포인터가 캐시 라인의 끝에 뻗어있을 수 있습니다. 이러한 정렬되지 않은 멤버에 액세스하려면 항상 두 번의 읽기 또는 쓰기가 필요하며 그럴 수 없습니다. 실제로 CLR 유형 확인 프로그램의 버그라고 생각하지만이 고비를 지나치는 데 도움이되지 않습니다.

확실히 32 비트 코드와 상호 운용하기 위해이 작업을 수행하고 디버그 빌드의 플랫폼 대상 설정을 올바르게 변경했지만 릴리스 빌드에서는 플랫폼 데이터 설정을 잊어 버렸습니다. 이는 구성 별 설정입니다. 쉬운 수정, 그냥 릴리스 구성에 대한 설정을 변경하십시오.

64 비트 모드에서 작동하려면 정말로 fixed char[16]으로 선언해야합니다.