Интерпретировать подписанный как unsigned
У меня есть значение, подобное этому:
int64_t s_val = SOME_SIGNED_VALUE;
Как я могу получить
uint64_t u_val
который имеет точно такой же битовый шаблон, что и s_val
, но обрабатывается как unsigned?
Это может быть очень просто, но, посмотрев на Stackoverflow и в другом месте, я не нашел ответа.
Ответы
Ответ 1
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
С++ Стандарт 4.7/2 гласит, что:
Если тип назначения не указан, результирующее значение представляет собой наименьшее беззнаковое целое, сравнимое с исходным целым числом (по модулю 2 n где n - количество бит, используемых для представления неподписанного типа). [Примечание. В представлении с двумя дополнениями это преобразование является концептуальным и нет изменений в битовой схеме (если нет усечения). ]
С другой стороны, Standard говорит, что "Отображение, выполняемое с помощью reinterpret_cast
, определяется реализацией. [Примечание: оно может или не может выдавать представление, отличное от исходного значения.]" (5.2.10/3). Поэтому я рекомендую использовать static_cast
.
Ответ 2
Обратите внимание, что вам вообще не нужен бросок. Для всех пререканий о том, будет ли бросок бить бит или нет для отрицательных представлений, одна вещь потерялась - бросок совершенно не нужен.
Из-за конверсий, которые C/С++ будет делать (и как определяется листинг), это:
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = s_val;
в точности эквивалентно:
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
Тем не менее, вам все равно может понравиться актерский состав, потому что он сигнализирует о намерениях. Тем не менее, я слышал, что он утверждал, что вы не должны использовать ненужные роли, потому что он может заставить замолчать компилятор в ситуациях, когда вам может понадобиться предупреждение.
Выберите свой яд.
Ответ 3
Вообще говоря, неважно, используете ли вы static_cast<int64_t>
или reinterpret_cast<int64_t>
. Пока вы работаете на процессоре, который использует два дополнения для представления отрицательных чисел, результат будет таким же. (Практически все современные процессоры используют это.) Под двумя дополнениями положительное число в подписанном int представляется одинаковым образом в unsigned int; если это отрицательное число, оно будет интерпретировано как большое положительное число в форме без знака.
В основном, то, что делает ваш бросок, говорит компилятору, что он создает различные инструкции по сборке при работе с этим значением. Например. существуют разные инструкции для умножения и деления для целых чисел со знаком. Хотя сложение и вычитание остаются неизменными (прочитайте ссылку на wikipedia, и вы поймете).
Ответ 4
Логический битовый шаблон (биты представления значений), то есть значения двоичных цифр могут быть сохранены только в том случае, если исходное подписанное значение было неотрицательным, поскольку отрицательные значения не могут быть представлены целой переменной без знака. Все, что вам нужно сделать, - назначить свое подписанное значение вашему неподписанному интегральному объекту, и вы закончили
uint64_t u_val = s_val;
Явный приведение не требуется, но может использоваться для подавления предупреждений компилятора.
Что касается физической битовой диаграммы (т.е. того, что вы видите в необработанной памяти, битов объекта-представления), вы просто не можете "преобразовать" ее таким образом. Язык С++ не предоставляет вам никаких методов преобразования, которые гарантировали бы сохранение физической битовой диаграммы. Все, что вы можете сделать, это переосмыслить память, занятую подписанным объектом, как неподписанный объект того же размера
STATIC_ASSERT(sizeof(int64_t) == sizeof(uint64_t));
uint64_t u_val = reinterpret_cast<uint64_t&>(s_val);
Опять же, это не преобразование, а скорее реинтерпретация памяти. Это не гарантируется, и это, как правило, является незаконным.
Ответ 5
Я согласен, что static_cast подходит в этом случае, но никто не упомянул очень похожий случай, когда static_cast не сохранил биты, как можно было бы ожидать.
char x = -1; // 255
unsigned int x2 = static_cast<unsigned int>(x); // 4294967295
unsigned int x3 = static_cast<unsigned int>(static_cast<unsigned char>(x)); // 255
Следите за расширением знака, когда вы отбрасываете небольшое значащее значение в большое значение без знака. Возможно, другие комбинации тоже уязвимы - я не думал, что все это происходит.
Ответ 6
Вы можете также reinterpret_cast
его или использовать union
:
union {
int64_t i64;
uint64_t ui64;
} variable;
variable.i64 = SOME_SIGNED_VALUE;
uint64_t a_copy = variable.ui64;
Ответ 7
Требуется поделиться этим современным, общим решением С++ 14. Первоначально было показано здесь.
template<class T>
auto as_unsigned(T t)
{
return std::make_unsigned_t<T>(t);
}
Что можно использовать следующим образом:
auto sx = int32_t{ 55 };
auto ux = as_unsigned(sx);
Вы можете увидеть это в действии здесь.