主要分享结构体,联合体,结构体内嵌套结构体、联合体的调用经历:
1C中的结构体的定义:
在实例中,下面的底层大佬给我的dll中定义是这样的:
//枚举
typedef enum {
Reader_NULL = 0x00,
Reader_Mobile_UWB = 0x01,
Reader_Shoulder_Rollcall = 0x02,
Reader_Handset_UWB = 0x03,
Reader_Handset_Rollcall = 0x04,
Reader_Sentry_UWB = 0x10,
Reader_Bluetooth = 0xF0,
} ReaderType;
//结构体
typedef struct {
ReaderType readerType;
uint32_t readerID;
uint32_t tagID;
uint32_t sequence; // 序号
uint8_t protoVer; // 协议版本号
uint32_t addr; // IN_ADDR
uint64_t time;
//嵌套匿名联合体
union {
//嵌套结构体
struct {
uint8_t mode;
uint16_t distance; // 单位:厘米
float voltage; // 单位:伏特
bool isMove;
bool isCut;
uint8_t version; // 硬件版本号
} TagStatus;
struct {
int result; // 读取、设置配置时,通过此值判断是否成功
uint8_t addr;
int32_t value;
int errcode;
} ConfigStatus;
};
} DevMsg;
这个结构体分析下来是这样的
struct
{
(一堆变量的声明)
union {
struct(1)
struct(2)
}
}
联合体我们知道是公用地址,也就是说union可以看成是一个结构体成员,在定义时,将struct(1)和struct(2)的存储地址相等就可以做出联合体的效果,至于结构体,在C#中本身就可以直接定义:
2下面是C#的代码:
public enum ReaderType
{
Reader_NULL = 0x00,
Reader_Mobile_UWB = 0x01,
Reader_Shoulder_Rollcall = 0x02,
Reader_Handset_UWB = 0x03,
Reader_Handset_Rollcall = 0x04,
Reader_Sentry_UWB = 0x10,
Reader_Bluetooth = 0xF0,
};
public struct DevMsg
{
public DevType device;
public ReaderType readerType;
public TagType tagType;
public MsgType type;
public UInt32 readerID;
public UInt32 tagID;
public UInt32 sequence; // 序号
public byte protoVer; // 协议版本号
public UInt32 addr; // IN_ADDR
public UInt64 time;
public TagStatus1 TagStatus;
public ConfigStatus1 ConfigStatus;
};
[StructLayout(LayoutKind.Explicit)]//重要
public struct TagStatus1
{
[FieldOffset(0)]//重点
public UInt16 distance; // 单位:厘米
[FieldOffset(2)]
public byte modex;
[FieldOffset(4)]
public Single voltage; // 单位:伏特
[FieldOffset(8)]
byte isMove;
[FieldOffset(12)]
byte isCut;
[FieldOffset(16)]
byte version; // 硬件版本号
};
[StructLayout(LayoutKind.Explicit)]
public struct ConfigStatus1
{
[FieldOffset(0)]
Int16 result; // 读取、设置配置时,通过此值判断是否成功
[FieldOffset(0)]
byte addr;
[FieldOffset(0)]
Int32 value;
[FieldOffset(0)]
Int16 errcode;
};
首先写两点疑问:
1:为什么要用分配存储地址的方式?
因为在union中,赋值不是通过名字的方式赋值的,而是通过存储位置来给值得。
2:为什么代码中的fieldoffset给的地址如此凌乱?
因为经过多次测试,发现作者琢磨不透其的传值规律,有时byte占2位,有时又占4位,所以一不做二不休,咱们直接去看内存里面是咱们传值的,我们再来把这个地址填上。
3C#获得变量地址:
int size = Marshal.SizeOf(msg);
IntPtr intPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(msg, intPtr, true);
这个时候intptr就是我们结构体的地址了。
4C#查看变量内存
在运行时,点击 调试->窗口->内存 内存1-4随便选一个都可以
接着把你刚刚获得的地址输入进去,尽可以看到内存中存储的数据了
就是如上图所示,根据dll的协议,对照着,就可以完美的接受dll传过来的结构体数据了。