Android 如何从二进制数据中读取数字,跨平台(C/C++)?
我有原始二进制数据块,实际上是CBOR编码的。要读取数字,我使用常见形式,如:Android 如何从二进制数据中读取数字,跨平台(C/C++)?,android,c++,ios,cross-platform,Android,C++,Ios,Cross Platform,我有原始二进制数据块,实际上是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 } 是否有任何平台无关
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
}
是否有任何平台无关的解决方案不会影响性能?警告-此答案假设机器的整数表示为little endian,问题也是如此
唯一独立于平台且正确的方法是使用memcpy。你不需要工会
不要担心效率。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);
}
注:余弦
通过添加运行时端点检查,可以使此解决方案真正可移植。实际上,检查将被省略,因为编译器将看穿它:
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;
}
警告-这个答案假设机器的整数表示是小端点,问题也是如此
唯一独立于平台且正确的方法是使用memcpy。你不需要工会
不要担心效率。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);
}
注:余弦
通过添加运行时端点检查,可以使此解决方案真正可移植。实际上,检查将被省略,因为编译器将看穿它:
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;
}
我认为这可能是你将得到的最好结果。使用适当的反序列化,而不是这些未定义的行为重新解释。您已经遇到了一些问题,可能还会有更多问题。我认为这可能是您将得到的最好结果。请使用适当的反序列化,而不是这些未定义的行为重新解释。你已经遇到一些问题了,可能还会有更多。胡说!唯一兼容且独立于平台的方法是使用位移位实现SEERIALIzation!memcpy不关心endianess或表示。endianess不是问题,因为我需要的所有编译器都有转换字节顺序的内在机制。当没有内部变量时,我会回退到位移位。@olaf我知道endian的ness问题,并假设OP知道它。我正在解决将字节流转换为整数的问题。我将在答案中添加一条警告。@Olaf已更新,并添加了一个endian验证解决方案,其优点是在一个小小的endian x86上仍然100%有效。@SBKarr:使用正确的序列化首先有什么问题?一个好的编译器不会产生比重新解释的黑客方法更糟糕的代码,但是不需要测试,也不需要其他依赖于目标的东西。胡说八道!唯一兼容且独立于平台的方法是使用位移位实现SEERIALIzation!memcpy不关心endianess或表示。endianess不是问题,因为我需要的所有编译器都有转换字节顺序的内在机制。当没有内部变量时,我会回退到位移位。@olaf我知道endian的ness问题,并假设OP知道它。我正在解决将字节流转换为整数的问题。我将在答案中添加一条警告。@Olaf已更新,并添加了一个endian验证解决方案,其优点是在一个小小的endian x86上仍然100%有效。@SBKarr:使用正确的序列化首先有什么问题?一个好的编译器不会生成比重新解释的黑客方法更糟糕的代码,但是不需要测试,也不需要其他依赖于目标的东西。
main:
subq $8, %rsp
call get_bytes()
movq (%rax), %rdi
call emit(unsigned long)
xorl %eax, %eax
addq $8, %rsp
ret