본문 바로가기

.NET/C#

C# - string 배열을 담은 구조체를 직렬화하는 방법

출처: http://sysnet.pe.kr/221115005092

C# 구조체나 클래스 할당메모리 크기구하기;  http://lab.gamecodi.com/board/zboard.php?no=5096&id=GAMECODILAB_QnA_etc


위의 질문을 정리하면, 다음과 같은 구조체를 크기가 고정된 배열로 만들어 Marshal.SizeOf로 구하고 싶다는 것입니다.

[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct DirInfo{    string[] DirNames;    string[] Time;    string[] size;}


이런 문제는, 여러분들이 Marshal.SizeOf 코드의 개발자라고 생각하고 풀어 보면 됩니다.

첫 번째 문제는 string입니다. 도대체 string에 몇 개의 문자가 있을지 알 수 없으므로 고정된 크기를 산정할 수 없습니다. 또한 배열이라는 것도 마찬가지입니다. 배열의 크기가 정해지지 않았는데 당연히 고정된 크기를 구할 수 없습니다.

따라서 방법은, 크기를 고정시키기만 하면 됩니다.

우선, 가장 쉬운 방법으로 약간의 구조를 바꿔 다음과 같은 식으로 항목 별로 크기를 고정하는 것입니다.

[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct DirItem{    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]    public string DirName;    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]    public string Time;    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]    public string size;}[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct DirInfo{    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]    public DirItem [] Items;}


이런 경우에는 Marshal.SizeOf도 크기를 구할 수 있으므로 잘 동작합니다.

static void Main(string[] args){    DirItem dir = new DirItem();    Console.WriteLine(Marshal.SizeOf(dir)); // 3072 == 1024 * 3    DirInfo dir2 = new DirInfo();    Console.WriteLine(Marshal.SizeOf(dir2)); // 3145728 == 3072 * 1024}





반면, (소스 코드를 변경할 수 없는) C++ DLL 측에서 구조가 이미 고정되어 있는 경우라면 다음과 같은 방법으로 우회할 수 있습니다.

public struct FixedString{    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]    string Item;}[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct DirInfo{    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]    FixedString[] DirNames;    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]    FixedString[] Time;    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]    FixedString[] size;}


역시 크기는 동일하게 계산됩니다.

static void Main(string[] args){    DirInfo dir = new DirInfo();    Console.WriteLine(Marshal.SizeOf(dir)); // 3145728}





그 외에 다음의 읽을거리도 있으니 참고하세요. ^^

Win32 Interop - 크기가 정해지지 않은 배열을 C++에서 C#으로 전달하는 경우; http://www.sysnet.pe.kr/2/0/737C#에서 Union 구조체 다루기; http://www.sysnet.pe.kr/2/0/728How to Interop DISPPARAMS; http://www.sysnet.pe.kr/2/0/617[in,out] 배열을 C# 에서 C/C++ 로 넘기는 방법 - 두번째 이야기; http://www.sysnet.pe.kr/2/0/811[in,out] 배열을 C# 에서 C/C++ 로 넘기는 방법; http://www.sysnet.pe.kr/2/0/810구조체 포인터 인자에 대한 P/Invoke 정의; http://www.sysnet.pe.kr/2/0/912