Вот что я хочу сделать:
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?
Потому что это не то, что 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
и неявное преобразование, вы ожидаете, что оно будет работать в любой разумной реализации, но на самом деле это не гарантировано.
Нет. reinterpret_cast
в основном предназначен для переосмысления существующего бита хранилища как другого типа, чем он есть. Многие из этих интерпретаций зависят от реализации, и стандарт перечисляет определенный (довольно длинный, чтобы процитировать здесь) список того, что можно сделать с помощью reinterpret_cast
(в основном приведение между различными указателями / ссылочными типами), но говорит:
Никакое другое преобразование не может быть выполнено явно, используя
reinterpret_cast.
В вашем случае вы, вероятно, хотите преобразование типов, а не реинтерпретацию существующего хранилища. использование static_cast
для этого.
использование static_cast
в этих случаях. Я полагаю, что разработчики языка во всей своей мудрости решили, что это не считается «недостаточно безопасным», чтобы оправдать reinterpret_cast
,
Из стандарта C ++ 11 (N3376) 5.2.10.1:
Преобразования, которые могут быть выполнены явно с использованием reinterpret_cast, перечислены ниже. нет
другое преобразование может быть выполнено явно с использованием reinterpret_cast.
Единственное допустимое преобразование из целочисленного типа в целочисленный тип является infact, если типы идентичны.
Другие связаны с указателями.
reinterpret_cast
используется для переосмысления хранения объекта как другого объекта. Если вы не хотите проходить через стандартную формулировку, вы можете найти все, что reinterpret_cast
сможет сделать Вот. Как правило, вы можете помнить, что вам нужно работать с типами указателей.
Итак, если вы действительно хотите переосмыслить биты, используемые для вашего uint64_t
как int64_t
затем сделайте это:
int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber);
Однако, если вы просто хотите преобразовать объект, сохранив его значение, если это возможно … просто сделайте то, что предлагает компилятор, и используйте static_cast
вместо.
Почему он не компилируется?
Потому что ни один из типов не является указателем.
оба типа имеют одинаковую длину в битах,
Почему это имеет значение? Если бы они были указателями, возможно, имело бы значение, что они указывали на вещи одинакового размера, но они не указатели.
разве не для этого предназначен reinterpret_cast?
Нет, reinterpret_cast
для приведения указателей. Вы можете сделать то, что вы хотите, поставив &
внутри гипса и *
вне этого. Вот для чего нужен реинтерпретация актеров.