C#中struct的位元組對齊、轉換操作和複製為位元據(byte[])

來源:互聯網
上載者:User

在做C#與其它程式通訊的系統時,往往會使用struc操作結構化的資料(如資料包等)。

本文簡要提出一些使用思路,歡迎各位大牛賜教。

一、STRUCT結構設計

當資料的結構確定時,總結為下面兩種情況:

1、資料長度確定(包括字串):

此時可以直接利用struct來構造資料包,比如:

        [StructLayout(LayoutKind.Sequential, Pack = 1)]        struct THeader        {            public short size;            public byte type;            public int seqno;        }        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]        struct TGSUpdateLadder        {            public THeader h;            public byte charlevel;            public uint charexplow;            public uint charexphigh;            public byte charclass;            public ushort charstatus;            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]            public string charname;        }

StructLayout用來確定布局方式,其中的Sequential表示在記憶體中按位元組對齊連續儲存,Pack指定位元組對齊(即幾位元組對齊),CharSet用來指定ByValTStr等字串類型在複製到非託管記憶體(或從非託管記憶體中複製)時使用的字元集。

MarshalAs用來指明下一個欄位在複製到非託管地區(或從非託管記憶體中複製)時的轉換方式和長度。

除ByValTStr外,常用的還有:

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.SysInt)]        public int[] reserved;

ByValArray可用來轉換一個長度確定的數組,SizeConst指明數組元素個數,ArraySubType指明數組中每個元素的類型。

2、資料中字串長度不確定:

有時通訊中的字串沒有固定長度,在包中以\0結尾,這時如果非要使用struct表示,可以使用CustomMarshaler,但這將導致該struct在複製到非託管記憶體或從非託管記憶體複製時無法確定struct的長度(所有CustomMarshaler的長度都不可計算,不知道這一設計的原因是什麼,但可以手動計算),在此省略。

臨時解決辦法是僅在struct中定義定長的欄位,在解析資料包時動態截取字串。

二、STRUCT與非託管記憶體

        public byte[] StructToBytes(object obj)        {            int rawsize = Marshal.SizeOf(obj);            IntPtr buffer = Marshal.AllocHGlobal(rawsize);            Marshal.StructureToPtr(obj, buffer, false);            byte[] rawdatas = new byte[rawsize];            Marshal.Copy(buffer, rawdatas, 0, rawsize);            Marshal.FreeHGlobal(buffer);            return rawdatas;        }        public object BytesToStruct(byte[] buf, int len, Type type)        {            object rtn;            IntPtr buffer = Marshal.AllocHGlobal(len);            Marshal.Copy(buf, 0, buffer, len);            rtn = Marshal.PtrToStructure(buffer, type);            Marshal.FreeHGlobal(buffer);            return rtn;        }        public void BytesToStruct(byte[] buf, int len, object rtn)        {            IntPtr buffer = Marshal.AllocHGlobal(len);            Marshal.Copy(buf, 0, buffer, len);            Marshal.PtrToStructure(buffer, rtn);            Marshal.FreeHGlobal(buffer);        }        public void BytesToStruct(byte[] buf, object rtn)        {            BytesToStruct(buf, buf.Length, rtn);        }        public object BytesToStruct(byte[] buf, Type type)        {            return BytesToStruct(buf, buf.Length, type);        }

上面的代碼可以將struct根據記憶體布局方式轉換為byte[],或從byte[]轉換為特定類型的struct。

調用方式如:

        byte[] SendBuf = StructToBytes(rpacket);
        TGSGetDataRequest packet = new TGSGetDataRequest();        packet = (TGSGetDataRequest)BytesToStruct((byte[])buf, Marshal.SizeOf(packet), packet.GetType());

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.