如何准确地将NSData转换为struct

时间:2016-04-08 02:42:26

标签: ios nsdata bluetooth-lowenergy

我从设备获取数据(BLE):< 840100ec d5045715 00010014 00240018 00>

第二个字节无法准确转换。像这样:

enter image description here

但我可以使用Uint8阵列,为什么?谢谢。 enter image description here

像这样的代码:

    // 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;

2 个答案:

答案 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) ...

等等。