简体   繁体   中英

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:

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:

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 . 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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