2009-11-06 2 views
6

char 버퍼를 관리되지 않는 함수에 전달해야하는 C# 프로그램이 있습니다. 안정적으로 작동하는 것으로 보이는 두 가지 방법을 찾았지만 어느 것을 선택해야할지 모르겠습니다.C#에서 관리되지 않는 함수 호출 : StringBuilder를 전달해야합니까? 아니면 안전하지 않은 코드를 사용해야합니까?

다음은 관리되지 않는 함수의 서명입니다.

extern "C" __declspec(dllexport) int getNextResponse(char *buffer); 

첫 번째 옵션은 다음과 같이 버퍼를 StringBuilder로 정의하는 것입니다.

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse(StringBuilder buffer); 

//in main method body... 
StringBuilder sb = new StringBuilder(" ", 65536); 
int rc = getNextResponse(sb); 

이 간단하고, 상호 운용성 층 그냥 문자로 모두 StringBuilder를 정렬 화되어 그것을 작동, 나는 모두 StringBuilder가 무대 뒤에서 버퍼를 가지고 있기 때문에 그것이 작동하는 이유는 기본적으로 이해 생각, 그래서 (나는 가정) *.

다른 옵션은 안전하지 않은 코드를 사용하고 있습니다.

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse(byte* buffer); 

//separate method... 
private static unsafe int runGetNextResponse(byte[] buffer) 
{ 
    fixed (byte* p = buffer) 
    { 
     int rc = getNextResponse(p); 
     return rc; 
    }    
} 

//in main method body... 
byte[] b = new byte[65536]; 
int rc = runGetNextResponse(b); 

두 번째 방법은 코드가 더 많지만 진행 상황에 대해서도 더 분명합니다.

기본적으로 동일한 두 가지 방법이 있습니까? 하나를 선택할 이유가 있습니까?

답변

8

StringBuilder 버전을 사용하는 것이 좋습니다.

둘 사이에는 큰 차이가 없으며 안전하지 않은 코드를 사용하면 거의 깨끗하지 않습니다.

제 생각에는 핵심 라이브러리 클래스를 사용하여 문제를 해결하는 방법이 있기 때문에 안전하지 않은 코드를 명확하고 (필요한) 혜택없이 사용하는 것은 조기 최적화입니다.

+0

가비지 콜렉터가 getNextResponse 실행 중에 고정 명령문없이 전달 된 StringBuilder를 재 할당하면 어떻게됩니까? 가져온 함수에서 사용되는 모든 포인터 매개 변수는 고정되어야합니까? 또는 나는 seomthing을 놓치고 있냐? – Luca

2

나는 분명히 무게를다는 것이 불가능하지만, 나는 내 자신의 경험을 나눌 수 있습니다. StringBuilder 메서드를 독점적으로 사용하여 문제가 발생하지 않았습니다. 나는 그것의 더 간단한 코드와 안전하지 않은 회피를 좋아한다.

3

StringBuilder를 사용하는 것이 좋지만 하나의주의 사항이 있습니다.

var sb = new StringBuilder(); 
sb.Append("Hello World"); 
int result = getNextResponse(sb); 
Console.WriteLine(result); 
someOtherMethod(); // kaboom: The GC could have already destroyed the string builder. 

안전하지 않은 방법을 보장 : 이제 관리 측면에서 살펴 보자 이제

char* globalPointer; 

int getNextResponse(char *buffer) { 
    globalPointer = buffer; 
    return 0; 
} 

void someOtherMethod() { 
    printf("%s\n", globalPointer); 
} 

: 당신의 getNextResponse 방법에 일부 정적 변수에 포인터를 저장하고 다른 방법을 사용하는 것이 예를 들어 상상 메모리 위치가 이동하지 않을 것입니다 :

byte[] buffer = Encoding.UTF8.GetBytes("Hello World"); 
fixed (byte* p = buffer) 
{ 
    int result = getNextResponse(p); 
    Console.WriteLine(result); 
    someOtherMethod(); // works fine as the buffer address is pinned down in memory 
} 

이 경우 안전하지 않은 버전이 더 잘 작동합니다.

0

버퍼의 데이터가 실제로 무엇인지에 따라 다릅니다. 문자 데이터 인 경우 StringBuilder 방식을 사용하십시오. 바이너리 데이터의 경우 바이트 배열을 대신 사용하지만 안전하지 않은 메서드는 사용하지 마십시오. 과장된 '안전하지 않은'것에 대한 과장된 두려움은 다소 어리 석으며 보장 할 때 사용하지 않을 이유가 없지만이 경우 불필요합니다. 사용 :

//at class level... 
[DllImport("mydll.dll")] 
static extern int getNextResponse([In, Out] byte[] buffer); 

//in main method body... 
byte[] buffer = new byte[65536]; 
int rc = getNextResponse(buffer); 
1

마샬링 비용에 따라 다릅니다. 마샬링을 많이하거나 마샬링되는 데이터가 큰 경우 매번 문자열 작성기 버퍼를 작성/파괴하는 대신 버퍼를 재사용 할 수 있습니다.

관련 문제