我从设备获取数据(BLE):< 840100ec d5045715 00010014 00240018 00>
但第二个字节无法准确转换。像这样:
像这样的代码: // I got the data:<840100ec d5045715 00010014 00240018 00>
case SPK_FEEDBACK_HistoryDataPort:
// Log
NSLog(@"receive data:%@", [NSData dataWithBytes:originalCommandBytes length:sizeof(D2MHistoryDataPort)]);
// originalCommandBytes dataType:UInt8 *
D2MHistoryDataPort *historyData = (D2MHistoryDataPort *)originalCommandBytes;
// Log
NSLog(@"收到硬件返回的0x%x指令(历史数据体): 历史数据包的索引:%d; 时间戳:%d; 步数:%d; 卡路里:%d; 距离:%d; 睡眠:%d; 运动时长:%d",
historyData->cmd,
historyData->index,
(unsigned int)historyData->timeStamp,
historyData->steps,
historyData->calories,
historyData->distance,
historyData->sleep,
historyData->duration);
break;
// I declare this struct in another class
typedef struct {
UInt8 cmd;
UInt16 index;
UInt32 timeStamp;
UInt16 steps;// 步数
UInt16 calories;// 卡路里
UInt16 distance;// 距离,单位m
UInt16 sleep;// 睡眠
UInt16 duration;// 运动时长,单位minute
} D2MHistoryDataPort;
答案 0 :(得分:2)
编译器如何在内存中布置结构的各个字段取决于实现。通常,编译器必须添加填充以正确对齐字段,甚至可能对它们进行重新排序(通过对相同大小的字段进行分组)以减少所需的填充和结构的整体大小。
您可以使用__attribute__((packed))
:
typedef struct __attribute__((packed)) {
UInt8 cmd;
UInt16 index;
UInt32 timeStamp;
UInt16 steps;// 步数
UInt16 calories;// 卡路里
UInt16 distance;// 距离,单位m
UInt16 sleep;// 睡眠
UInt16 duration;// 运动时长,单位minute
} D2MHistoryDataPort;
答案 1 :(得分:0)
你正在做的事情非常有效。您正在尝试获取结构,假设您可以将其解释为字节序列,将其写入并将其读回。那不行。从编译器版本之间具有不同布局的结构开始,介于32位和64位编译器之间,依此类推。人们在90年代就知道这是一个坏主意。
使用NSCoding协议。或者将数据转换为JSON。不要试图将结构解释为字节序列。
如果绝对无法避免使用NSData,这就是安全的工作方式:
步骤1:定义外部数据格式。外部数据格式不是“无论编译器决定布局我的结构”。外部数据格式是“一个无符号字节cmd;两个无符号字节索引,最高有效字节优先.4个无符号字节时间戳,最高有效字节优先,表示自1904年1月1日以来的秒数,......”等等。
然后读取结构,获取指向第一个字节的指针,检查是否有足够的字节,并写入
mystruct.cmd = p [0];
mystruct.index = (p [1] << 8) | p [2];
mystruct.timeStamp = (p [3] << 24) | (p [4] << 16) ...
等等。