日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#中结构体定义并转换字节数组

發布時間:2023/12/1 C# 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#中结构体定义并转换字节数组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ref: https://www.cnblogs.com/dafanjoy/p/7818126.html

C#中結構體定義并轉換字節數組

? ? ? ?最近的項目在做socket通信報文解析的時候,用到了結構體與字節數組的轉換;由于客戶端采用C++開發,服務端采用C#開發,所以雙方必須保證各自定義結構體成員類型和長度一致才能保證報文解析的正確性,這一點非常重要。

? ? ? ?首先是結構體定義,一些基本的數據類型,C#與C++都是可以匹配的:

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]public struct Head{public ushort proMagic; //包起始標記:固定0x7e7epublic ushort proPackLen; //包長度:包頭 + 數據區 + 包尾長度,注意不要超過最大長度限制public long proSrcAddr; //源地址:不使用,填0public ushort proSrcPort; //源地址端口:不使用,填0public long proDstAddr; //目的地址:不使用,填0public ushort proDstPort; //目的端口:不使用,填0public ushort proCmdCode; //命令碼:參見以上命令碼定義public ushort proVersion; //版本號:不使用,填1public char proSerial; //報文序號:一條報文實例對應一個序號,不同報文疊加,0-255往復public ushort proPackSum; //總包數:當包長超過最大長度限制時,需要拆包,大包拆小包總數,不拆默認1public ushort proPackId; //當前包號:對應以上總包數的小包標識,不拆默認0}

? ? ? ?一、首先是?[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)],這是C#引用非托管的C/C++的DLL的一種定義定義結構體的方式,主要是為了內存中排序,LayoutKind有兩個屬性Sequential和Explicit,Sequential表示順序存儲,結構體內數據在內存中都是順序存放的,CharSet=CharSet.Ansi表示編碼方式。這都是為了使用非托管的指針準備的,這兩點大家記住就可以。

? ? ? ?需要注意的是?Pack = 1 這個特性,它代表了結構體的字節對齊方式,在實際開發中,C++開發環境開始默認是2字節對齊方式 ,拿上面報文包頭結構體為例,char類型在雖然在內存中至占用一個字節,但在結構體轉為字節數組時,系統會自動補齊兩個字節,所以如果C#這面定義為Pack=1,C++默認為2字節對齊的話,雙方結構體會出現長度不一致的情況,相互轉換時必然會發生錯位,所以需要大家都默認1字節對齊的方式,C#定義Pack=1,C++ 添加?#pragma pack 1,保證結構體中字節對齊方式一致。

? ? ? ?二、數組的定義,結構體中每個成員的長度都是需要明確的,因為內存需要根據這個分配空間,而C#結構體中數組是無法進行初始化的,這里我們需要在成員聲明時進行定義;

/// <summary>/// 終端信息查詢/// </summary>[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]public struct PackTerminalSearch5001{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]/// <summary>/// 終端編號/// </summary>public string stationCode;[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]/// <summary>/// 回復指令/// </summary>public Byte[] order;}/// <summary>/// 終端信息數據/// </summary>[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]public struct PackTerminalSearch3004{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]/// <summary>/// 終端編號/// </summary>public string stationCode;/// <summary>/// 終端IP/// </summary>public long terminalIP;/// <summary>/// 終端端口/// </summary>public ushort terminalPort;/// <summary>/// 中心IP/// </summary>public long serverIP;/// <summary>/// 測站端口/// </summary>public ushort serverPort;/// <summary>/// 磁盤信息數組/// </summary>[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]public PackDiskInfo[] diskInfoArray;}/// <summary>/// 磁盤信息/// </summary>[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]public struct PackDiskInfo{/// <summary>/// 盤符/// </summary>public char drive;/// <summary>/// 總空間/// </summary>public double totalSize;/// <summary>/// 可用空間/// </summary>public double usableSize;}

? ? ? ? 上面的代碼需要注意的是string類型實際為Char[6]長度的數組,實際使用中只能有效的使用前5個字符,因為char[6]最后一位默認\0;

? ? ? ? 三、結構體與字節數組的互轉

   PackTerminalSearch5001 info;info.stationCode = "12345";info.order = new byte[6] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };Byte[] recv = StructToBytes(info);object obj = BytesToStuct(recv, typeof(PackTerminalSearch5001));PackTerminalSearch5001 info5001 = (PackTerminalSearch5001)obj;byte[] order = info5001.order;


<summary>/// 結構體轉byte數組/// </summary>/// <param name="structObj">要轉換的結構體</param>/// <returns>轉換后的byte數組</returns>public static byte[] StructToBytes(object structObj){//得到結構體的大小int size = Marshal.SizeOf(structObj);//創建byte數組byte[] bytes = new byte[size];//分配結構體大小的內存空間IntPtr structPtr = Marshal.AllocHGlobal(size);//將結構體拷到分配好的內存空間Marshal.StructureToPtr(structObj, structPtr, false);//從內存空間拷到byte數組Marshal.Copy(structPtr, bytes, 0, size);//釋放內存空間Marshal.FreeHGlobal(structPtr);//返回byte數組return bytes;}/// <summary>/// byte數組轉結構體/// </summary>/// <param name="bytes">byte數組</param>/// <param name="type">結構體類型</param>/// <returns>轉換后的結構體</returns>public static object BytesToStuct(byte[] bytes, Type type){//得到結構體的大小int size = Marshal.SizeOf(type);//byte數組長度小于結構體的大小if (size > bytes.Length){//返回空return null;}//分配結構體大小的內存空間IntPtr structPtr = Marshal.AllocHGlobal(size);//將byte數組拷到分配好的內存空間Marshal.Copy(bytes, 0, structPtr, size);//將內存空間轉換為目標結構體object obj = Marshal.PtrToStructure(structPtr, type);//釋放內存空間Marshal.FreeHGlobal(structPtr);//返回結構體return obj;}

?

?

?

轉載于:https://www.cnblogs.com/carl2380/p/9900609.html

總結

以上是生活随笔為你收集整理的C#中结构体定义并转换字节数组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。