ios - 切片时返回错误索引值的数据类型
问题描述
我正在尝试将一些二进制块解码为各种固定宽度的整数。删减数据的格式为 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])
我相信这与字节在内存中未对齐的事实有关?我已经阅读了许多与未对齐负载(例如1、2)相关的论坛帖子,但建议的解决方案似乎都没有解决这个问题:
尽管我无法弄清楚是什么导致了这种怪癖,但对于我的一生来说?如果有人有任何建议,我将不胜感激!
解决方案
所以看起来这最终只是数据文档的问题。
推荐阅读
- spring-cloud - 将 Spring Cloud Contract 验证发布到 Pact 代理
- java - 如何在 Android Studio 的 YouTube Web 视图中添加进度条
- google-drive-api - 使用 Drive API 下载文件时出错
- java - java中未排序数组列表中的最小元素
- sql - 如何计算货件的总行数
- android - SimpleDateFormat 在 Android Kitkat 中不起作用
- javascript - 如何使用javascript在点击时更新对象值
- actions-on-google - 在 Google Action 中“跨对话”存储数据
- tfs - ##[错误]错误:超出 GC 开销限制 - TFS 构建中的 SonarQube
- fish - 如何用 ] 替换文档中的最后一个字符?