티스토리 뷰




C/C++ 에서 작성한 코드를 C#에서 사용하기 위한 작업을 하던 중, 가변길이 포인터 배열에 대해 변환하는 방법에 대해 공유합니다. 


샘플로 만든 C 코드는 아래와 같습니다. 

typedef struct {
	char *name;
	int age;
} my_data;

typedef struct {
	int len;
	my_data **data_list;
} my_data_list;

__declspec(dllexport) void print_my_data_list(my_data_list *list)
{
	int i;

	if (!list) {
		printf("[ERROR] no list\n");
		return;
	}

	printf("[INFO] list length : %d\n", list->len);
	for (i = 0; i < list->len; i++) {
		print_my_data(list->data_list[i]);
	}
}



목표는 print_my_data_list 를 C#에서 호출하는 것입니다. 

my_data_list struct에는 my_data pointer array를 위한 double pointer 멤버(data_list)가 있습니다. 


이를 위한 C#코드는 아래와 같습니다. 

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct MyData
    {
        public string Name;
        public int Age;
    }

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct MyDataList
    {
        public int Len;
        public IntPtr List; // MyData pointer list (MyData **data_list)
    }

    class MyLib
    {
        [DllImport("MyLib.dll", EntryPoint = "print_my_data_list")]
        public extern static void PrintMyDataList(ref MyDataList list);

        [DllImport("MyLib.dll", EntryPoint = "print_my_data")]
        public extern static void PrintMyData(ref MyData data);
    }



배열의 길이가 고정이었다면 ConstSize로 미리 만들 수 있겠지만, 가변 길이 배열이기 떄문에 IntPtr로 선언하였습니다. 

이 포인터(IntPtr)의 크기를 배열의 길이 x 포인터(IntPtr)의 크기로 Alloc하고, 

배열 인덱스 위치에 MyData struct data를 alloc합니다. 


코드는 아래와 같습니다.

IntPtr ptr;
MyData[] data = {
    new MyData() { Name = "aaa", Age = 10 },
    new MyData() { Name = "bbb", Age = 20 },
    new MyData() { Name = "ccc", Age = 30 }
};

MyDataList list = new MyDataList();
list.Len = data.Length;

// 포인터의 크기 * 배열 길이만큼 Alloc
list.List = Marshal.AllocHGlobal(Marshal.SizeOf() * data.Length);

try
{
    for (int i = 0; i < data.Length; i++)
    {
        // MyData 마샬링
        ptr = Marshal.AllocHGlobal(Marshal.SizeOf(data[0]));
        Marshal.StructureToPtr(data[i], ptr, false);

        // list[포인터크기 * 배열 index] 위치에 포인터 복사
        Marshal.StructureToPtr(ptr, (IntPtr)((int)list.List + Marshal.SizeOf() * i), false);
    }

    MyLib.PrintMyDataList(ref list);
}
catch (Exception e)
{
    Console.Write("Error: " + e.Message);
}

실행을 해보면 잘 동작하는 것을 확인할 수 있습니다. 





반응형
댓글