我最近一直在为稍微修改过的 Abstract Syntax Notation 实现一个专门的解析器。规范说整数被编码为一个八位字节数组,这些八位字节将被解释为二进制补码整数。

因此,起初我认为将其反序列化为实际 C++ int 的最佳方法是简单地从 0 值开始,然后将每个八位字节与如下值进行 OR 运算:

uint64_t value = 0;
int shift = 0;
std::vector<uint8_t> octets = { /* some values */ };

for (auto it = octets.rbegin(); it != octets.rend(); ++shift, ++it)
{
  value |= uint64_t(*it) << (shift * 8);
}

这会给我留下一个存储在 value 中的位模式,然后我可以通过强制转换将其解释为有符号(二进制补码)整数:
int64_t signed_value = static_cast<int64_t>(value);

但我突然想到,这真的依赖于实现定义的行为。 C++ doesn't guarantee that signed integers are represented as two's complement 。因此,为了将编码整数的实际值作为 C++ int64_t ,我需要实际计算位模式中每个第 N 位的 2^N 的总和,同时考虑符号位。当我知道大部分时间都应该使用强制转换时,这似乎有点傻。

这里是否有更好的解决方案,既便携又高效?

最佳答案

如果您的解决方案有效,我认为您可以使用一些元编程来测试您的平台是一个补码还是两个补码。

struct is_ones_complement {
    static const bool value = ( (1 & -1) == 0);
}

然后,您可以编写一个可内联的转换函数:
template<bool is_ones_complement>
uint64_t convert_impl(const std::vector<uint8_t>& vec);

template<>
uint64_t convert_impl<true>(const std::vector<uint8_t>& vec) {
    // Your specialization for 1's-complement platforms
}

template<>
uint64_t convert_impl<false>(const std::vector<uint8_t>& vec) {
    // Your specialization for 2's-complement platforms
}

inline uint64_t convert(const std::vector<uint8_t>& vec) {
    return convert_impl<is_ones_complement::value>(vec);
}

未经测试,但它应该工作。

关于c++ - 二进制补码数表示,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17621466/

10-14 12:29