Generally, defining a binary data format using C-struct seems to be a bad idea.
Please check how
MSG_t is layout in the byte stream.
Format 1:
Code Block | +--+--+--+--+--+--+--+--+--+--+--+--+--+-- |
| | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|... |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+-- |
| |sig |len |type |data | |
| +-----+-----+-----+-----------+ |
Or
Format 2:
Code Block | +--+--+--+--+--+--+--+--+--+--+--+--+--+-- |
| | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|... |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+-- |
| |sig |len |type | |data | |
| +-----+-----+-----+-----+-----------+ |
Many compiles put two-byte padding after
type, to align
data to 32-bit boundary. But that depends on the compiler, CPU architecture or compiling flags.
But in communications, people do not like putting unused bytes.
You also need to care about endianness.
In communication within the same device, you can expect all multi-byte data have the same endianness, so you can program your code using CPU-endian.
But in TCP communications, the two nodes on the internet may have different CPU-endian. And there are many people who prefers big-endian for binary data format on the internet, as you know
network order, even if the CPU is little-endian.
So, if you mean
this as including
cast myData.bytes onto a struct, it is a wrong approach.
The first thing you need is defining the binary data format without using C-struct, specifying endianness explicitly.
(Also specify paddings explicitly, if exists.)
In the example below I assume something like this:
Code Block | offset|number of bytes|endianness |field name |
| ------+---------------|-------------|---------- |
| +0| 2|little endian|sig |
| +2| 2|little endian|len |
| +4| 2|little endian|type |
| +6| 4|little endian|data |
| ------+---------------|-------------|---------- |
With the data format like this, you can write some code as follows:
Code Block | class DataReader { |
| var data: Data |
| var offset: Int = 0 |
| |
| init(data: Data) { |
| self.data = data |
| } |
| |
| func readLittleEndian<T: FixedWidthInteger>()->T { |
| var rawValue: T = 0 |
| _ = withUnsafeMutableBytes(of: &rawValue) {rawBufPtr in |
| data.copyBytes(to: rawBufPtr, from: offset...) |
| } |
| offset += MemoryLayout<T>.size |
| |
| return T(littleEndian: rawValue) |
| } |
| } |
|
| //Sample data |
| let data: Data? = Data([ |
| 0x12, 0x34, |
| 0x56, 0x78, |
| 0x9A, 0xBC, |
| 0xDE, 0xF0, 0x12, 0x34]) |
|
| if let myData = data { |
| var myStruct = MSG_t() |
|
| let reader = DataReader(data: myData) |
| myStruct.sig = reader.readLittleEndian() |
| myStruct.len = reader.readLittleEndian() |
| myStruct.type = reader.readLittleEndian() |
| myStruct.data = reader.readLittleEndian() |
| |
| print(String(format: "%04X", myStruct.sig)) |
| print(String(format: "%04X", myStruct.len)) |
| print(String(format: "%04X", myStruct.type)) |
| print(String(format: "%08X", myStruct.data)) |
| |
| if myStruct.sig == CORRECT_MSG_SIG { |
| // do soemthig with the message... |
| } |
| } |
(Assuming
MSG_t is defined in C-style header and imported into Swift.)