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

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

Я понимаю, что reinterpret_cast опасен, я просто делаю это, чтобы проверить это. У меня есть следующий код:

int x = 0;
double y = reinterpret_cast<double>(x);

Когда я пытаюсь скомпилировать программу, выдает ошибку

недопустимое приведение типа 'float' к типу 'double

Что происходит? Я думал, что reinterpret_cast - это мошенническое приведение, которое вы можете использовать для преобразования яблок в подводные лодки, почему этот простой состав не скомпилируется?

4b9b3361

Ответ 1

Назначив y значению, возвращаемому приложением, вы действительно не набрасываете значение x, вы его конвертируете. То есть, y не указывает на x и делает вид, что указывает на поплавок. Conversion создает новое значение типа float и присваивает ему значение от x. Существует несколько способов сделать это преобразование в С++, среди которых:

int main()
{
    int x = 42;
    float f = static_cast<float>(x);
    float f2 = (float)x;
    float f3 = float(x);
    float f4 = x;
    return 0;
}

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

Теперь, если вы действительно хотите сделать вид, что x - это float, тогда вы действительно хотите использовать x, выполнив следующее:

#include <iostream>
using namespace std;

int main()
{
    int x = 42;
    float* pf = reinterpret_cast<float*>(&x);
    (*pf)++;
    cout << *pf;
    return 0;
}

Вы можете видеть, насколько это опасно. Фактически, вывод, когда я запускаю это на моей машине, 1, который явно не 42 + 1.

Ответ 2

В С++ reinterpret_cast может выполняться только определенный набор преобразований, явно указанный в спецификации языка. Короче говоря, reinterpret_cast может выполнять только преобразования указателя на указатель и преобразования ссылки на ссылку (плюс преобразования указателя на целое и целочисленные в указатели). Это согласуется с намерением, выраженным в самом имени приведения: оно предназначено для использования для интерпретации указателя/ссылки.

То, что вы пытаетесь сделать, это не переинтерпретация. Если вы хотите переосмыслить int как double, вам придется преобразовать его в ссылочный тип

double y = reinterpret_cast<double&>(x); 

хотя эквивалентная реинтерпретация на основе указателей, вероятно, более явная

double y = *reinterpret_cast<double*>(&x); // same as above

Обратите внимание, что хотя reinterpret_cast может преобразовать типы ссылок/указателей, фактическая попытка считывания данных через результирующий указатель/указатель вызывает поведение undefined.

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

Итак, в конце концов, все сводится к тому, чего вы пытались достичь. Реинтерпретация памяти? См. Выше. Какое-то более значимое преобразование int to double? Если это так, reinterpret_cast вам не поможет.

Ответ 3

reinterpret_cast не является общепринятым. В соответствии с разделом 5.2.10.1 раздела С++ 03:

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

И нет ничего перечисленного, описывающего преобразование между целыми и плавающими типами (или между целыми типами, даже это незаконно reinterpret_cast<long>(int(3));)

Ответ 4

Если вы пытаетесь преобразовать биты вашего int в представление double, вам нужно указать адрес, а не значение. Вы также должны убедиться, что размеры соответствуют:

uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);

Ответ 5

Компилятор отвергает то, что вы написали как бессмыслицу, потому что int и double могут быть объектами разных размеров. Таким образом, вы можете добиться такого же эффекта, хотя это, безусловно, опасно:

int x = 0;
double y = *reinterpret_cast<double*>(&x);

Это потенциально опасно, потому что если x и y - разные размеры (скажем, int - четыре байта, а double - восемь байт), то при разыменовании восьми байтов памяти в &x заполните y, вы получите четыре байта x и четыре байта... что будет дальше в памяти (возможно, начало y, или мусор, или что-то еще полностью.)

Если вы хотите преобразовать целое число в double, используйте static_cast и он выполнит преобразование.

Если вы хотите получить доступ к битовому образцу x, добавьте к некоторому удобному типу указателя (скажем, byte*) и получите доступ к sizeof(int) / sizeof(byte):

byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
  // do something with p[i]
}

Ответ 6

Reinterpret cast позволяет вам переинтерпретировать блок памяти как другой тип. Это должно выполняться по указателям или ссылкам:

int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f );   // !!

Другое дело, что на самом деле это довольно опасный состав, причем не только из-за странных значений, которые выходят в качестве результатов, либо из-за несовместимости утверждений выше, а потому, что, если типы имеют разные размеры, и вы переосмысливаете из " source 'to' destination ', любая операция над реинтерпретированной ссылкой/указателем будет иметь доступ к sizeof(destination) байтам. Если sizeof(destination)>sizeof(source), то это будет выходить за пределы реальной памяти переменных, потенциально убивая ваше приложение или перезаписывая другие переменные, отличные от источника или назначения:

struct test {
   int x;
   int y;
};
test t = { 10, 20 };
double & d = reinterpret_cast<double&>( t.x );
d = 1.0/3.0;
assert( t.x != 10 ); // most probably at least.
asswet( t.y != 20 );

Ответ 7

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

От msdn:

Оператор reinterpret_cast может быть используется для преобразований, таких как char * to int * или One_class * Unrelated_class *, которые по своей сути небезопасный.

Результат reinterpret_cast нельзя безопасно использовать для чего-либо за исключением того, оригинальный type. Другие виды использования: лучший, непереносимый.

Ответ 8

Приведение int в double не требует приведения. Компилятор выполнит назначение неявно.

Реинтерпрет_каст используется с указателями и ссылками, например, отбрасывая int * в double *.

Ответ 9

Это интересно. Может быть, он делает неявное преобразование из int в float, прежде чем он попытается выполнить двойное нажатие. типы int и float имеют одинаковый размер в байтах (в зависимости от вашей системы).

Ответ 10

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

double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof(dest));