简体   繁体   English

二进制补码表示

[英]Two's complement number representation

I've recently been implementing a specialized parser for a slightly modified Abstract Syntax Notation . 我最近一直在为一个略微修改的抽象语法表示法实现一个专门的解析器。 The specification says that integers are encoded as an array of octets which are to be interpreted as a binary two's-complement integer. 规范说整数被编码为八位字节数组,它们被解释为二进制二进制补码整数。

So, at first I thought the best way to unserialize this into an actual C++ int would be to simply start with a value of 0, and then OR each octet with the value like: 所以,起初我认为将其反序列化为实际的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);
}

This would leave me with a bit pattern stored in value , which I could then interpret as a signed (two's-complement) integer by casting it: 这会让我有一个存储在value的位模式,然后我可以通过强制它将其解释为带符号(二进制补码)整数:

int64_t signed_value = static_cast<int64_t>(value);

But it occurred to me that this is really relying on implementation-defined behavior. 但在我看来,这实际上是依赖于实现定义的行为。 C++ doesn't guarantee that signed integers are represented as two's complement . C ++不保证有符号整数表示为二进制补码 So, to get the actual value of the encoded integer as a C++ int64_t , I'd need to actually calculate the summation of 2^N for each Nth bit in the bit pattern, taking into account the sign bit. 因此,为了将编码整数的实际值作为C ++ int64_t ,我需要实际计算位模式中每个第N位的2 ^ N的总和,同时考虑符号位。 This seems kind of silly when I know that casting should just work most of the time. 当我知道铸造应该在大多数时间工作时,这似乎有点傻。

Is there a better solution here that would be both portable and efficient? 这里有更好的解决方案既便携又高效?

If your solution works, I think you can use a bit of metaprogramming to test whether your platform is one's complement or two's complement. 如果您的解决方案有效,我认为您可以使用一些元编程来测试您的平台是一个补码还是两个补码。

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

And then, you can write an inlinable conversion function: 然后,您可以编写一个无限转换函数:

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

Untested, but it should work. 未经测试,但它应该工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM