티스토리 뷰
C/C++ 에서 작성한 코드를 C#에서 사용하기 위한 작업을 하던 중, 가변길이 포인터 배열에 대해 변환하는 방법에 대해 공유합니다.
샘플로 만든 C 코드는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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#코드는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [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합니다.
코드는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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<intptr>() * 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<intptr>() * i), false ); } MyLib.PrintMyDataList( ref list); } catch (Exception e) { Console.Write( "Error: " + e.Message); } </intptr></intptr> |
실행을 해보면 잘 동작하는 것을 확인할 수 있습니다.
반응형