Как вывести строку из нативного кода
Имея встроенную функцию, которая возвращает строку (как char *) по параметру, что было бы лучшим вариантом между предварительным выделением char * через управляемый код и передачей его по параметру и выделением char * из собственного кода, а затем выпуском это из с #?
не могли бы вы объяснить мне, почему я должен использовать один над другим? Пожалуйста, отвечайте, только если есть определенная причина, чтобы предпочесть решение другому. Если вместо этого все решения в порядке, мой вопрос также может считаться ответом.
В качестве бонуса я хотел бы знать, как я должен выделить переменную char * из C# в первом случае (с использованием класса Marshal или с простым new или с StringBuilder, как я часто вижу в других ответах?) И как я должен удалить указатель, если вместо этого я создаю переменную char * из собственного кода во втором случае.
1 ответ
Обычно не рекомендуется возвращать char*
от функции C и ожидаем, что он будет отменен вызывающим. Вызывающая сторона может этого не делать (правильно или вообще) и, таким образом, утечка памяти. Один из распространенных способов избежать этого (как его используют OpenGL, OpenCL и другие библиотеки, которые я видел) - объявить прототип следующим образом:
int GetString(char* str, int* len);
с такой реализацией:
int GetString(char* str, int* len)
{
if (str == NULL)
{
len = internal_get_string_length();
return 0; // No errors
}
else
{
if (len <= internal_get_string_length())
return -1; // not enough space in str
char* internal_str = internal_get_string_ptr();
strcpy(str, internal_str);
return 0;
}
}
В документации будет указано, что если str
NULL, длина возвращаемой строки возвращается в len
, В противном случае указатель str
как ожидается, будет содержать столько символов, сколько требуется. Чтобы использовать его, пользователь вызывает функцию дважды, один раз с NULL для str
и Int для len
затем снова с выделенным массивом символов, пока len
, Возможный прототип для P/Invoking такого рода функции:
// Declaration
[DllImport("myDll.dll")]
int GetString(StringBuilder sb, ref int len);
// Usage
int length;
GetString(null, length);
var sb = new StringBuilder(length); // Set capacity
GetString(sb, length);
Console.WriteLine(sb.ToString()); // Do stuff with C# string
Надеюсь, это поможет!