Интерпретация uint16_t как int16_t - PullRequest
0 голосов
/ 19 сентября 2011

Существует ли портативный и безопасный способ интерпретировать битовый шаблон, созданный boost::uint16_t, как boost::int16_t? У меня есть uint16_t, который, как я знаю, представляет 16-разрядное целое число со знаком, закодированное как little-endian. Мне нужно сделать некоторую арифметику со знаком для этого значения, так что есть ли способ убедить компилятор, что это уже значение со знаком?

Если я не ошибаюсь, static_cast<int16_t> преобразует значение, возможно, изменяя его битовый шаблон.

Ответы [ 6 ]

2 голосов
/ 19 сентября 2011

Если вы ищете что-то отличное от приведения, скопируйте его представление памяти в boost::int16_t, начиная с того, что оно представляет для начала.

Редактировать: Если вам нужно, чтобы он работал на машине с прямым порядком байтов, просто скопируйте байты назад. Используйте std::copy и std::reverse.

1 голос
/ 13 июня 2012

Просто используйте статическое приведение.Изменение битового шаблона оказывается именно тем, что вам нужно, если вы оказались на платформе, которая определяет их по-разному.

reinterpret_cast или любое эквивалентное приведение указателя не определено (не определено реализацией).Это означает, что компилятор может делать неприятные вещи, такие как кэширование неопределенной формы в реестре, и пропустить обновление.Кроме того, если бы вы работали на платформе, где битовые комбинации были другими, то обход конверсии оставил бы вас с мусором (точно так же, как притворство с плавающей точкой - это int и добавление к нему 1).

Более подробная информация на Преобразование со знаком в беззнаковое в C - всегда ли это безопасно? но сводка C окольным путем определяет статическое приведение (фактически обычное приведение C) как то, что вы получаете, обрабатывая биты одинаково на x86(который использует дополнение до двух.)

Не играйте в компилятор с компилятором (это всегда работало на этом компиляторе, так что, конечно, они не нарушат код каждого при его изменении).История доказала, что вы неправы.

0 голосов
/ 19 сентября 2011

Как другой способ, лучший способ максимизировать (но не гарантировать) переносимость состоит в том, чтобы хранить эти 16-разрядные целые числа со знаком как 16-разрядные целые числа со знаком в сетевом порядке, а не как 16-разрядные целые числа без знака в порядке с прямым порядком байтов. Это накладывает бремя на целевую машину, чтобы иметь возможность преобразовывать эти целые числа со знаком 16-битного сетевого порядка в целые числа со 16-битными знаками в нативной форме. Не каждая машина поддерживает эту возможность, но большинство машин, которые могут подключиться к сети, поддерживают эту функцию. В конце концов, этот файл должен попасть на целевую машину по какому-то механизму, так что вероятность того, что он поймет сетевой порядок, довольно высока.

С другой стороны, если вы переносите этот двоичный файл на какой-то встроенный компьютер через какой-то собственный последовательный интерфейс, ответ на вопрос о переносимости будет таким же, как вы получите, когда скажете своему врачу: это. "

0 голосов
/ 19 сентября 2011

Редактировать
Чтобы избежать разногласий по поводу *(int16_t)(&input_value), я изменил последний оператор в блоке кода на memcpy и добавил *(int16_t)(&input_value) в качестве дополнения.(Как и наоборот).

На машине с прямым порядком байтов вам нужно будет поменять байты, а затем интерпретировать их как целое число со знаком:

if (big_endian()) {
  input_value = (uint16_t)((input_value & 0xff00u) >> 8) |
                (uint16_t)((input_value & 0x00ffu) << 8);
}
int16_t signed_value;
std::memcpy (&signed_value, &input_value, sizeof(int16_t));

На большинстве компьютеров вы можетеизмените вызов на memcpy на signed_value = *(int16_t)(&input_value);.Строго говоря, это неопределенное поведение.Это также чрезвычайно широко используемая идиома.Почти все компиляторы делают «правильные вещи» с этим утверждением.Но, как всегда в случае с расширениями языка, YMMV.

0 голосов
/ 19 сентября 2011

Полагаю, *(boost::int16_t*)(&signedvalue) сработает, если ваша системная архитектура не имеет порядкового номера по умолчанию. endian ness изменит поведение, так как после вышеупомянутой операции cpu будет обрабатывать значение со знаком как специфичное для архитектуры значение boost :: int16_t (то есть, если ваша архитектура с прямым порядком байтов, она пойдет не так).

0 голосов
/ 19 сентября 2011

Замаскируйте все, кроме знакового бита, сохраните его в int со знаком, затем установите знак, используя бит знака.

...