P / Invoking int [] из c ++ в C # показывает случайные большие числа вместо оригинальных членов массива - PullRequest
0 голосов
/ 17 мая 2019

У меня следующий код C ++:

int nCount[5] = {0, 1, 2, 3, 4};    
return &nCount[0];

Я получаю этот код в слое C # P / Invoke со следующим кодом:

[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
 public extern static IntPtr read_array_adapter();

Что хорошо работает. Но когда я запускаю код C # ниже:

int[] result = new int[5];
Marshal.Copy(ptr, result, 0, 5); 

Заполняет результат массива несколькими случайными большими числами, которые выглядят так:

int[]{1663918692,1852139884,1970351988,1936417641,244554078}

, который не имеет отношения к моему исходному массиву в C ++, который выглядит как {0,1,2,3,4} Есть идеи, что Marshal.Copy может делать для заполнения результатов такого рода?

1 Ответ

1 голос
/ 17 мая 2019

Если вы хотите, чтобы память переживала область действия функции, и не хотите использовать глобальные переменные, то вы должны выделить ее не из стека (локальной переменной).

Вы можете использовать любой распределитель,вы можете использовать тот, который уже известен .NET, или если вы используете другой, специфичный для C ++ или вашей платформы, то вы также должны предоставить другую функцию P / Invokable для освобождения, что-то вроде этого:

C ++

int* read_array_adapter()
{
    int nCount[5] = {0, 1, 2, 3, 4};    
    return AllocateAndCopy(...);
}

void free_array_adapter(int *) // or a generic pointer of course...
{
    Free(...);
}

C #

static void Main(string[] args)
{
    var ptr = read_array_adapter();
    var result = new int[5];
    Marshal.Copy(ptr, result, 0, 5);
    free_array_adapter(ptr);
}

[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
public extern static IntPtr read_array_adapter();

[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
public extern static void free_array_adapter(IntPtr ptr);

Вы также можете использовать известный распределитель между .NET и C / C ++, но это зависит от платформы (Windows, Linux и т. Д.): https://www.mono -project.com / docs / advanced / pinvoke /

Вот пример реализации с malloc / free duo в C:

int* read_array_adapter()
{
    int nCount[5] = { 0, 1, 2, 3, 4 };
    int* p = (int*)malloc(5 * 4);
    memcpy(p, nCount, 5 * 4);
    return p;
}

void free_array_adapter(void * ptr)
{
    free(ptr);
}
...