gpt4 book ai didi

android - 如何从二进制数据中读取数字,跨平台/C++)?

转载 作者:行者123 更新时间:2023-11-30 01:43:27 25 4
gpt4 key购买 nike

我有原始二进制数据 block (实际上,CBOR 编码)。要读取数字,我使用常见的形式,例如:

template <typename T> // T can be uint64_t, double, uint32_t, etc...
auto read(const uint8_t *ptr) -> T {
return *((T *)(ptr)); // all endianess-aware functions will be performed later
}

此解决方案适用于 x86/x86_64 PC 和 arm/arm64 iOS。但是,在 arm/armv7 Android 上,clang 编译器处于默认发布优化级别 (-Os),我收到 SIGBUS对于类型,代码 1(未对齐读取)大于一个字节。我用另一个解决方案解决了这个问题:

template <typename T>
auto read(const uint8_t *ptr) -> T {
union {
uint8_t buf[sizeof(T)];
T value;
} u;
memcpy(u.buf, ptr, sizeof(T));
return u.value;
}

是否有任何独立于平台且不会影响性能的解决方案?

最佳答案

警告 - 这个答案假设机器的整数表示是小端的,问题也是如此。

唯一平台独立且正确的方法是使用 memcpy。你不需要 union 。

不用担心效率。 memcpy 是一个神奇的函数,编译器会“做正确的事”。

针对 x86 编译的示例:

#include <cstring>
#include <cstdint>

template <typename T>
auto read(const uint8_t *ptr) -> T {
T result;
std::memcpy(&result, ptr, sizeof(T));
return result;
}

extern const uint8_t* get_bytes();
extern void emit(std::uint64_t);

int main()
{
auto x = read<std::uint64_t>(get_bytes());
emit(x);

}

产生汇编器:

main:
subq $8, %rsp
call get_bytes()
movq (%rax), %rdi ; note - memcpy utterly elided
call emit(unsigned long)
xorl %eax, %eax
addq $8, %rsp
ret

注意:字节顺序

您可以通过添加运行时字节顺序检查使该解决方案真正具有可移植性。实际上,检查将被忽略,因为编译器会看穿它:

constexpr bool is_little_endian()
{
short int number = 0x1;
char *numPtr = (char*)&number;
return (numPtr[0] == 1);
}


template <typename T>
auto read(const uint8_t *ptr) -> T {
T result = 0;
if (is_little_endian())
{
std::memcpy(&result, ptr, sizeof(result));
}
else
{
for (T i = 0 ; i < sizeof(T) ; ++i)
{
result += *ptr++ << 8*i;
}
}
return result;
}

生成的机器码没有改变:

main:
subq $8, %rsp
call get_bytes()
movq (%rax), %rdi
call emit(unsigned long)
xorl %eax, %eax
addq $8, %rsp
ret

关于android - 如何从二进制数据中读取数字,跨平台/C++)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37776115/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com