Подтвердить что ты не робот

Интерпретировать подписанный как unsigned

У меня есть значение, подобное этому:

int64_t s_val = SOME_SIGNED_VALUE;

Как я могу получить

uint64_t u_val

который имеет точно такой же битовый шаблон, что и s_val, но обрабатывается как unsigned?

Это может быть очень просто, но, посмотрев на Stackoverflow и в другом месте, я не нашел ответа.

4b9b3361

Ответ 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);

Вы можете увидеть это в действии здесь.