Почему я не могу повторно интерпретировать uint для int?

Вот что я хочу сделать:

const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);

Где randomUintNumber имеет тип uint64_t,

Ошибка (MSVC 2010):

ошибка C2440: «reinterpret_cast»: невозможно преобразовать из «const uint64_t»
в ‘int64_t’ 1> Преобразование является допустимым стандартным преобразованием,
который может быть выполнен неявно или с использованием static_cast, C-style
приведение или приведение в функциональном стиле

Почему он не компилируется? оба типа имеют одинаковую длину в битах, не для чего предназначен reinterpret_cast?

11

Решение

Потому что это не то, что reinterpret_cast для. Все разрешенные преобразования с reinterpret_cast включать указатели или ссылки, за исключением того, что может быть целочисленный или перечислимый тип reinterpret_cast к себе. Это все определено в стандарте, [expr.reinterpret.cast],

Я не уверен, чего вы здесь добиваетесь, но если вы хотите randomIntNumber иметь то же значение, что и randomUintNumberтогда делай

const int64_t randomIntNumber = randomUintNumber;

Если это приводит к предупреждению компилятора или если вы просто хотите быть более явным, то:

const int64_t randomIntNumber = static_cast<int64_t>(randomUintNumber);

Результат приведения имеет то же значение, что и ввод, если randomUintNumber меньше 263. В противном случае результат определяется реализацией, но я ожидаю, что все известные реализации, которые имеют int64_t определим это, чтобы сделать очевидную вещь: результат эквивалентен входу по модулю 264.


Если ты хочешь randomIntNumber иметь тот же битовый шаблон, что и randomUintNumberтогда вы можете сделать это:

int64_t tmp;
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp));
const int64_t randomIntNumber = tmp;

поскольку int64_t гарантированно использовать представление в два дополнения, вы бы надежда что реализация определяет static_cast иметь тот же результат, что и для значений вне диапазона uint64_t, Но это на самом деле не гарантируется в стандартном AFAIK.

Даже если randomUintNumber константа времени компиляции, к сожалению, здесь randomIntNumber является не константа времени компиляции. Но тогда, насколько «случайным» является константа времени компиляции? 😉

Если вам нужно обойти это, и вы не доверяете реализации разумно конвертировать неподписанные значения вне диапазона в подписанные типы, тогда что-то вроде этого:

const int64_t randomIntNumber =
randomUintNumber <= INT64_MAX ?
(int64_t) randomUintNumber :
(int64_t) (randomUintNumber - INT64_MAX - 1) + INT64_MIN;

Теперь я за то, чтобы писать действительно переносимый код, где это возможно, но, тем не менее, я думаю, что это граничит с паранойей.


Кстати, вы могли бы написать это:

const int64_t randomIntNumber = reinterpret_cast<int64_t&>(randomUintNumber);

или эквивалентно:

const int64_t randomIntNumber = *reinterpret_cast<int64_t*>(&randomUintNumber);

Это не совсем гарантировано, потому что, где они существуют int64_t а также uint64_t гарантированно будет подписанным типом и беззнаковым типом того же размера, на самом деле они не гарантированно будут подписанной и беззнаковой версиями стандартного целочисленного типа. Так что это зависит от реализации, нарушает ли этот код строгий псевдоним. Код, нарушающий строгое псевдоним, имеет неопределенное поведение. Следующее делает не нарушать строгое псевдонимы, и это нормально при условии, что битовый шаблон в randomUintNumber является действительным представлением значения long long:

unsigned long long x = 0;
const long long y = reinterpret_cast<long long &>(x);

Так что на реализациях, где int64_t а также uint64_t являются typedefs для long long а также unsigned long longтогда мой reinterpret_cast все в порядке. Как и в случае с преобразованием, определенным реализацией, значений вне диапазона в подписанные типы, вы бы ожидать что разумная вещь для реализации должна сделать их соответствующими типами со знаком / без знака. Так вроде static_cast и неявное преобразование, вы ожидаете, что оно будет работать в любой разумной реализации, но на самом деле это не гарантировано.

20

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

Нет. reinterpret_cast в основном предназначен для переосмысления существующего бита хранилища как другого типа, чем он есть. Многие из этих интерпретаций зависят от реализации, и стандарт перечисляет определенный (довольно длинный, чтобы процитировать здесь) список того, что можно сделать с помощью reinterpret_cast (в основном приведение между различными указателями / ссылочными типами), но говорит:

Никакое другое преобразование не может быть выполнено явно, используя
reinterpret_cast.

В вашем случае вы, вероятно, хотите преобразование типов, а не реинтерпретацию существующего хранилища. использование static_cast для этого.

3

использование static_cast в этих случаях. Я полагаю, что разработчики языка во всей своей мудрости решили, что это не считается «недостаточно безопасным», чтобы оправдать reinterpret_cast,

2

Из стандарта C ++ 11 (N3376) 5.2.10.1:

Преобразования, которые могут быть выполнены явно с использованием reinterpret_cast, перечислены ниже. нет
другое преобразование может быть выполнено явно с использованием reinterpret_cast.

Единственное допустимое преобразование из целочисленного типа в целочисленный тип является infact, если типы идентичны.

Другие связаны с указателями.

1

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

Итак, если вы действительно хотите переосмыслить биты, используемые для вашего uint64_t как int64_tзатем сделайте это:

int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber);

Однако, если вы просто хотите преобразовать объект, сохранив его значение, если это возможно … просто сделайте то, что предлагает компилятор, и используйте static_cast вместо.

1

Почему он не компилируется?

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

оба типа имеют одинаковую длину в битах,

Почему это имеет значение? Если бы они были указателями, возможно, имело бы значение, что они указывали на вещи одинакового размера, но они не указатели.

разве не для этого предназначен reinterpret_cast?

Нет, reinterpret_cast для приведения указателей. Вы можете сделать то, что вы хотите, поставив & внутри гипса и * вне этого. Вот для чего нужен реинтерпретация актеров.

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