Представление числа в дополнение к двум

Недавно я внедрил специализированный парсер для слегка модифицированного Абстрактная синтаксическая нотация. В спецификации говорится, что целые числа кодируются как массив октетов, которые должны интерпретироваться как двоичное целое число с дополнением до двух.

Итак, сначала я подумал, что лучший способ сделать сериализацию в настоящем C ++ int было бы просто начать со значения 0, а затем ИЛИ каждый октет со значением вроде:

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 ++ не гарантирует, что целые числа со знаком представляются как дополнение к двум. Итак, чтобы получить фактическое значение закодированного целого числа как C ++ int64_tМне нужно было бы на самом деле рассчитать суммирование 2 ^ N для каждого N-го бита в битовой комбинации с учетом знакового бита. Это кажется глупым, когда я знаю, что кастинг должен работать большую часть времени.

Есть ли здесь лучшее решение, которое было бы одновременно портативным и эффективным?

4

Решение

Если ваше решение работает, я думаю, что вы можете использовать немного метапрограммирования, чтобы проверить, является ли ваша платформа дополнением одного или двух.

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

Не проверено, но это должно работать.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]