主要分享結構體,聯合體,結構體內嵌套結構體、聯合體的調用經歷:
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傳過來的結構體數據了。