C 使用struct直接轉換下位機資料

2022-01-10 11:52:46 字數 3170 閱讀 8304

編寫上位機與下位機通訊的時候,涉及到協議的轉換,比較多會使用到二進位制。傳統的方法,是將資料整體獲取到byte陣列中,然後逐字節對資料進行解析。這樣操作工作量比較大,對於較長資料段更容易計算位置出錯。

其實,對於下位機給出通訊的資料結構的情況下,可以直接使用c#的struct將資料直接轉換。需要使用到marshal

假定下位機(c語言編寫)給到我們的資料結構是這個,傳輸方式為小端方式

typedef struct  dataitem_t;
首先需要定義乙個struct:

[structlayout(layoutkind.sequential, size = 64, pack = 1)]

public struct hardwaredata

然後使用以下**進行轉換

// code from 

/// /// converts byte to struct

///

public static t rawdeserialize(byte rawdata, int position)

/// /// converts a struct to byte

///

public static byte rawserialize(object anything)

提示是對齊的錯誤,這個和編譯的時候使用的32bit和64位是相關的,詳細資料封送對齊的操作我不就詳細說了,貼下**。

//強制指定x86編譯

[structlayout(layoutkind.explicit, size = 64, pack = 1)]

public struct dataitem

強制指定x64編譯沒有成功,因為資料對齊後和從下位機上來的資料長度是不符的。

微軟不是很推薦使用layoutkind.explicit,如果非要用並且不想指定平台的話,可以使用指標來操作,當然,這個需要unsafe

var item = rawdeserialize(tail.toarray(), 0);

unsafe

}[structlayout(layoutkind.explicit, size = 64, pack = 1)]

public struct dataitem

感覺寫起來還是很麻煩,既然用上了unsafe,就乾脆直接一點。

[structlayout(layoutkind.sequential, pack = 1)]

public unsafe struct dataitem

這樣,獲得陣列可以直接正常訪問,不再需要unsafe了。

資料解析作為上下位機通訊的常用操作,使用struct直接轉換資料可以大大簡化工作量。建議還是使用layoutkind.sequential來進行封送資料,有關於資料在託管與非託管中的轉換,可以詳細看看微軟有關互操作的內容。

以上**在.net 5.0下編譯通過並能正常執行。

注意上面的前提要求是位元組序為小端位元組序(一般計算機都是小端位元組序),對於大端位元組序傳送過來的資料,需要進行位元組序轉換。我找到一處**寫的很好:

//code from 

public static class footest

[structlayout(layoutkind.sequential, pack = 1)]

public struct foo

public static void test()

;foo sample = new foo()

;var bytes_le = dummy.structtobytes(sample, endianness.littleendian);

var restoredleasle = dummy.bytestostruct(bytes_le, endianness.littleendian);

var restoredleasbe = dummy.bytestostruct(bytes_le, endianness.bigendian);

var bytes_be = dummy.structtobytes(sample, endianness.bigendian);

var restoredbeasle = dummy.bytestostruct(bytes_be, endianness.littleendian);

var restoredbeasbe = dummy.bytestostruct(bytes_be, endianness.bigendian);

debug.assert(sample.equals(restoredleasle));

debug.assert(sample.equals(restoredbeasbe));

debug.assert(restoredbeasle.equals(restoredleasbe));

}public enum endianness

private static void maybeadjustendianness(type type, byte data, endianness endianness, int startoffset = 0)

foreach (var field in type.getfields())

else}}

internal static t bytestostruct(byte rawdata, endianness endianness) where t : struct

finally

return result;

}internal static byte structtobytes(t data, endianness endianness) where t : struct

finally

maybeadjustendianness(typeof(t), rawdata, endianness);

return rawdata;

}}

C 結構體與陣列的資料轉換 下(socket)

引言 經過上章的講解,已經知道了記憶體對齊。那麼我們言歸正傳 一 結構體 陣列 二 陣列 結構體 由於陣列儲存是連續的,所以在相互轉換的時候記憶體也要對齊 struct st temp st temp temp temp.iage 4 temp.iyear 2018 temp.imonth 6 in...

C 中struct的使用

effective c 說將 c 視為乙個聯邦。c object oriented c template c stl 那麼討論 c 中的 struct 的使用,可以說就是c中 struct 的使用。struct point int x int y struct 宣告定義了一種資料型別。struct ...

c語言struct結構體強制型別轉換

1 無結構體標籤 struct gpio t 宣告了乙個無名結構體,並建立了乙個結構體變數gpio t 已分配空間 該方法只適合建立乙個結構體變數 typedef struct gpio t 靜態分配記憶體 gpio t gpioa 動態分配記憶體 gpio t gpioa gpio t mallo...