网站浏览器兼容性,重庆市工程造价信息网查询,广东专业网站建设,服务器网站怎么用C#字节对齐示例
结构体定义
[StructLayoutAttribute(LayoutKind.Sequential, CharSet CharSet.Ansi, Pack 1)]#xff0c;这是C#引用非托管的C/C的DLL的一种定义定义结构体的方式#xff0c;主要是为了内存中排序#xff0c;LayoutKind有两个属性Sequential和Explicit CharSet.Ansi, Pack 1)]这是C#引用非托管的C/C的DLL的一种定义定义结构体的方式主要是为了内存中排序LayoutKind有两个属性Sequential和ExplicitSequential表示顺序存储结构体内数据在内存中都是顺序存放的CharSetCharSet.Ansi表示编码方式。这都是为了使用非托管的指针准备的这两点大家记住就可以。
Pack 1 这个特性它代表了结构体的字节对齐方式在实际开发中C开发环境开始默认是2字节对齐方式 拿上面报文包头结构体为例char类型在虽然在内存中至占用一个字节但在结构体转为字节数组时系统会自动补齐两个字节所以如果C#这面定义为Pack1,C默认为2字节对齐的话双方结构体会出现长度不一致的情况相互转换时必然会发生错位所以需要大家都默认1字节对齐的方式C#定义Pack1,C 添加 #pragma pack 1保证结构体中字节对齐方式一致。
数组的定义结构体中每个成员的长度都是需要明确的因为内存需要根据这个分配空间而C#结构体中数组是无法进行初始化的这里我们需要在成员声明时进行定义
[StructLayout(LayoutKind.Sequential, CharSetCharSet.Ansi,Pack 1)]
public struct PackHeader
{public ushort packFlag;public ushort packlen;public ushort version;public ushort index;
}[StructLayout(LayoutKind.Sequential, CharSetCharSet.Ansi, Pack 1)]
public struct SendHeader
{public byte packFlag;[MarshalAs(UnmanagedType.ByValArray, SizeConst 3)]public byte[] space; // 数组指定长度public ushort beflen;
}byte[] 转结构体
using System.Runtime.InteropServices; // 引入命名空间
/// summary
/// 解析数据结构体
/// /summary
/// param namebuf/param
/// param namelen/param
/// param nametype/param
/// returns/returns
public static object BytesToStruct(byte[] buf, int len, Type type)
{object rtn;try{IntPtr buffer Marshal.AllocHGlobal(len);Marshal.Copy(buf, 0, buffer, len);rtn Marshal.PtrToStructure(buffer, type);Marshal.FreeHGlobal(buffer);return rtn;}catch (Exception){return null;}
}结构体转byte[] summary
/// 结构体转byte数组
/// /summary
/// param namestructObj要转换的结构体/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;
}C 字节对齐
字节对齐的好处加快变量在内存的存取速度。
VS, VC等编译器默认是#pragma pack(8)常注意gcc默认是#pragma pack(4)并且gcc只支持1,2,4对齐。
结构体的每个成员相对于结构体的首地址的偏移量都是基本成员大小的整数倍。比如
struct{int a; //4 首地址achar b; //1 第二个成员b相对于第一个成员a是整数倍double c; //8
}常用对齐pragma pack(1)方式与数据解析
字节对齐常用的是数据解析与数据封装pragma pack(1)是最常用的对齐方式之一。
#pragma once
#pragma pack(1)
typedef struct{unsigned short headerFlag;unsigned short len;unsigned char cmd;
} DataHeader,*PDataHeader;typedef struct{unsigned short val;
} DataHeart,*PDataHeart;typedef struct {unsigned char cmdNo;unsigned short timeSpan;unsigned char spaces[6];
}DataCmd, *PDataCmd;
#pragam pack()struct DataProtocUtils{// 解包示例bool ParseData(const char * buf,int len,int cmdNo){PDataHeader pheader;PDataCmd cmd;pheader (PDataHeader)buf;if(pheader-cmd 0x01){cmd (PDataCmd)(bufsizeof(DataHeader));cmdNo cmd-cmdNo;return true;}return false;}// 封包示例bool PackHeartToHost(unsigned short state,char * buf,int len){DataHeader header;header.headerFlag 0x3A3A;header.cmd 0x32;header.len 1sizeof(DataHeart); // len 不包括headerFlag、len、tail的长度// 协议定义时一定要说明否则会造成歧义DataHeart heart;heart.val state;char tail[2] {0xA3A3,0xA3A3}; // 包尾memcpy(buf,(char *)(header),sizeof(DataHeader));len sizeof(DataHeader);memcpy(bufleb,(char *)(heart),sizeof(DataHeart));len sizeof(DataHeart);memcpy(bufleb,tail,2); len2;return true;}
}