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

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

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

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

недопустимый бросок от типа 'плавает' для ввода 'дважды

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

62
задан Micha Wiedenmann 12 October 2018 в 12:59
поделиться

9 ответов

Присваивая y значению, возвращаемому преобразованием, вы на самом деле не преобразовываете значение x , а преобразуете его. То есть y не указывает на x и не делает вид, что указывает на float. Преобразование создает новое значение типа float и присваивает ему значение из x . Есть несколько способов выполнить это преобразование в C ++, среди них:

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 - это число с плавающей запятой, тогда вы действительно хотите преобразовать 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.

41
ответ дан 24 November 2019 в 16:47
поделиться

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

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

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

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

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

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

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

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

41
ответ дан 24 November 2019 в 16:47
поделиться

reinterpret_cast не является общим составом. В соответствии со спецификацией C ++ 03, раздел 5.2.10.1:

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

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

{{ 1}}
11
ответ дан 24 November 2019 в 16:47
поделиться

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

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

Другое дело, что это на самом деле довольно опасное приведение, не только из-за странных значений, получаемых как результаты, или из-за того, что утверждение выше не дает сбоя. , но поскольку если типы имеют разные размеры и вы переинтерпретируете типы «исходный» на «целевой», любая операция с переинтерпретированной ссылкой / указателем будет обращаться к байтам 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.
assert( t.y != 20 );
3
ответ дан 24 November 2019 в 16:47
поделиться

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

Из msdn:

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

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

1
ответ дан 24 November 2019 в 16:47
поделиться

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

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

0
ответ дан 24 November 2019 в 16:47
поделиться

Для бизнес-данных, если данные являются частными, я бы использовал защищенное соединение, в противном случае достаточно аутентификации форм.

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

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

Чтобы включить SSL (Secure Sockets Layer) для вашего веб-сайта, необходимо настроить сертификат, код или конфигурацию, которые не изменяются.

Я включил SSL для внутреннего веб-сервера, используя OpenSSL и ActivePerl из этого онлайн-руководства . Если это используется для большей аудитории (моя аудитория была менее 10 человек) и находится в открытом доступе, я предлагаю искать профессиональные альтернативы.

Это SSL и https один и тот же...

Не совсем, но они идут рука об руку! SSL обеспечивает шифрование и расшифровку данных при просмотре веб-сайта, https - это URI, необходимый для доступа к защищенному веб-сайту. При попытке доступа к http://secure.mydomain.com появится сообщение об ошибке.

Нужно ли подавать заявку с кем-то, чтобы получить какую-либо лицензию или что-то еще.

Вам нужно получить не лицензию, а сертификат. Можно найти компании, которые предлагают профессиональные услуги с защищенными веб-сайтами, например, VeriSign .

Нужно ли защищать все мои страницы или только страницу входа в систему...

После включения сертификата для mydomain.com каждая страница под * .mydomain.com будет защищена.

-121--787537-

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

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

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

0
ответ дан 24 November 2019 в 16:47
поделиться

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

uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
10
ответ дан 24 November 2019 в 16:47
поделиться

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

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

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

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

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

byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
  // do something with p[i]
}
3
ответ дан 24 November 2019 в 16:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: