reinterpret_cast



Исходя из имени этого оператора, он вводится для узкой специализации: "переосмыслить" значение, т.е. представить его в другом виде. Его используют для приведение несовместных типов: «указатель к объекту», «указатель к указателю». Из живого примера 1:

double  *pointer_f64 = new double(42);

int64_t *pointer_i64 = reinterpret_cast<int64_t *>(pointer_f64);

int64_t  value_i64   = reinterpret_cast<int64_t> (pointer_i64);

int32_t *pointer_i32 = reinterpret_cast<int32_t *>(value_i64);



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



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

void save(const double &hp)

{

file.write(reinterpret_cast<const uint8_t*>(&hp), sizeof(hp));

}



void load(double &hp)

{

file.read(reinterpret_cast<uint8_t*>(&hp), sizeof(hp));

}



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



Давайте попробуем увидеть, как расставлены биты в типе double в живом примере 2. При решении этой задачи можно воспользоваться готовой стандартной структурой std::bitset(unsigned long long) для распечатки битов. Однако, есть нюанс! Тип данных double можно привести к соразмерному unsigned long long двумя разными способами, которые дают совершенно разный результат.



Так, static_cast отбрасывает дробную часть и преобразует к целочисленному значению, а reinterpret_cast просто иначе интерпретирует расставленные биты. В следствие этого из 42.0 мы получаем не 42, а какое-то другое и явно отличное от исходного число: 4631107791820423168. Очень похоже на то, как мы иногда в шутку пытаемся услышать слова родного языка в иностранных песнях.



Однако, с точки зрения поставленной задачи, именно оно нам и нужно — тип unsigned long long просто выступает в роли «грузового контейнера» для транспортировки 64 битов, которые std::bitset потом благополучно печатает в консоль.



#cppcore