如何将 NSData 准确转换为 struct

How to convert NSData to struct accurately

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

但是第二个字节无法准确转换。喜欢这些:

但是我可以使用 Uint8 数组,为什么?谢谢。

像这样的代码:

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

编译器如何在内存中布置结构的各个字段取决于实现。通常编译器必须添加填充以正确对齐字段,它甚至可能会重新排序它们(通过对相同大小的字段进行分组)以减少所需的填充和结构的整体大小。

您可以使用 __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;

你做的肯定是行不通的。您正在尝试采用一个结构,假设您可以将其解释为一个字节序列,将其写入并读回。那是行不通的。从在编译器版本之间、32 位和 64 位编译器之间等具有不同布局的结构开始。人们在 90 年代就知道这是个坏主意。

使用 NSCoding 协议。或者将数据转换为JSON。不要试图将结构解释为字节序列。

如果您绝对无法避免使用 NSData,那么它的安全工作方式如下:

第一步:定义外部数据格式。外部数据格式不是 "whatever the compiler decided to layout my struct"。外部数据格式为"One unsigned byte cmd; two unsigned bytes index, most significant byte first. 4 unsigned bytes time stamp, most significant byte first, meaning the number of seconds since Jan 1st 1904, ... "等。

然后读取结构,获取指向第一个字节的指针,检查您是否有足够的字节,然后写入

mystruct.cmd = p [0];
mystruct.index = (p [1] << 8) | p [2];
mystruct.timeStamp = (p [3] << 24) | (p [4] << 16) ...

等等。