首页 > 解决方案 > 切片时返回错误索引值的数据类型

问题描述

我正在尝试将一些二进制块解码为各种固定宽度的整数。删减数据的格式为 5 个 UInt32,后跟 n 个 Int16。

我收到的每个块都有 1 个 UInt8 的初始字节,说明该有效负载的大小,然后是 244 个字节的实际数据。我的方法是丢弃这个初始字节,并使用以下代码将剩余数据附加到数据缓冲区:

let payload = data.advanced(by: 1)
payloadBuffer.append(payload)

在收到预期的总字节数(由 payloadBuffer.count 确定)后,我执行 crc32 检查以确保数据完整性,通过。

到目前为止一切都很好!

但是我注意到,如果我想对 payloadBuffer 进行切片并删除最初的 20 个字节以仅使用与上述索引类似的方法专注于 Int16,那么索引总是会减少 2 个字节。

因此,当我使用以下内容时,我似乎失去了初始 Int16 值:

let slicedBuffer = payload.advanced(by: 20)

但是,如果我使用:

let slicedBuffer = payload.advanced(by: 18)

我正确地获得了初始 Int16 值,即使您认为这是前一个 UInt32 的最后两个字节。

我正在使用以下代码来解码 slicedBuffer(通常带有字节偏移):

Int16(littleEndian: trimmedBuffer.withUnsafeBytes({ $0.load(as: Int16.self) }))

我尝试使用下标而不是.advanced(by:)以及.subData(in:),但仍然得到相同的结果。我还尝试了不同的方法来解码 Int16,例如以下一些方法:

let test = payloadBuffer.withUnsafeBytes { bytes -> Int16 in
    let int: Int16 = bytes.loadFixedWidthInteger(fromByteOffset: 20)
    return int
}

extension UnsafeRawBufferPointer {

    func loadFixedWidthInteger<T: FixedWidthInteger>(fromByteOffset offset: Int) -> T {
        var value: T = 0
        withUnsafeMutableBytes(of: &value) { valuePtr in
            valuePtr.copyBytes(from: UnsafeRawBufferPointer(start: self.baseAddress!.advanced(by: offset),
                                                            count: MemoryLayout<T>.size))
        }
        return value
    }
}

或者干脆...

Int16(bytes[21]) << 8 | Int16(bytes[20])

我相信这与字节在内存中未对齐的事实有关?我已经阅读了许多与未对齐负载(例如12)相关的论坛帖子,但建议的解决方案似乎都没有解决这个问题:

Swift 论坛 - 未对齐的负载

Stack Overflow - 创建对齐的字节数组

尽管我无法弄清楚是什么导致了这种怪癖,但对于我的一生来说?如果有人有任何建议,我将不胜感激!

标签: iosswiftiphonepointersbyte

解决方案


所以看起来这最终只是数据文档的问题。


推荐阅读