首页 文章

二进制补码表示

提问于
浏览
4

我最近一直在为一个略微修改的 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的总和,同时考虑符号位 . 当我知道铸造应该在大多数时间工作时,这似乎有点傻 .

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

1 回答

  • 1

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

    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);
    }
    

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

相关问题