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

Почему C-стиль работает, а reinterpret_cast - нет?

Итак, у меня есть два массива char

unsigned char v[2];

Я хочу показать значение v [0] как число от 0 до 255, но

cout << v[0] << endl; //prints some garbage

cout << (void*)v[0] << endl; //prints the right thing but in hex

Итак, я попробовал

cout << (int)v[0] << endl;

или

printf("%d\n", v[0]);

Это показывает, что я хотел, но мне это совсем не нравится. Также я не понимаю, почему это не работает:

cout << reinterpret_cast<int>(v[0]) << endl; //compiler error
4b9b3361

Ответ 1

(В терминах непрофессионала) reinterpret_cast используется для интерпретации битов объекта как другого типа в соответствии с реализацией. Вы не хотите этого: вы хотите преобразование (от char до int). Вместо этого используйте static_cast.

(Все возможные использования reinterpret_cast перечислены в 5.2.10; это не один из них.)

Ответ 2

cout << v[0] << endl; // prints some garbage

Не мусор, а символ, который представляет значение в v [0].

cout << (void*)v[0] << endl;

Это "преобразует" значение в v[0] в указатель (undefined поведение, поскольку он не был указателем для начала) и печатает значение этого указателя как шестнадцатеричное значение.

cout << (int)v[0] << endl;

Это преобразует значение в v[0] в int (четко определенный, просто продвигается до int) и отображает значение.

reinterpret_cast, как отмечали другие, имеет некоторые ограничения на то, что он может сделать. Правильный ответ - использовать static_cast<int>:

cout << static_cast<int>(v[0]) << endl;

Ответ 3

  • reinterpret_cast: "... позволяет преобразовать любой интегральный тип в любой тип указателя и наоборот ". Используйте это только для преобразования вещи, которые могут быть указателями на правильный тип указателя ( unsigned char явно не может быть указателем в чем-либо, кроме 8-битная система).

  • static_cast: используйте это, когда вы хотите, чтобы тип был другим type (например, float to int или unsigned char to int).

cout пытается напечатать unsigned char как код символа ASCII, поэтому преобразование в int через static_cast<int>(v[0]) - это правильная вещь.

Ответ 4

Как вы используете reinterpret_cast, вы пытаетесь прочитать char как int, и они не имеют одинакового размера.

Ответ 5

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

// NOTE: THIS IS UNDEFINED BEHAVIOR
cout << reinterpret_cast<int&>(v[0]) << endl; 

Это хорошо сформировано, но переинтерпретирует unsigned char как целочисленный объект, который не гарантированно работает (возможные проблемы варьируются от недопустимого выравнивания хранилища до несовместимых размеров - 1 байт против 4 байтов). Вы можете решить эти случаи, выполнив приведение (int)v[0], я думаю, что это прекрасно. Вы также можете сказать +v[0], который автоматически поддерживает значение (подписанное или без знака) int.

Ответ 6

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

reinterpret_cast также слабее, чем приведение в стиле C, но оно не строго сильнее static_cast; есть вещи, которые static_cast могут сделать, что reinterpret_cast не может. Вы столкнулись с одним из них.

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

В общем случае reinterpret_cast преобразует ваше значение в "удерживание", а значение удержания - это реализация, которая определена в лучшем случае, и часто ее использование - это поведение undefined.

Итак, вы хотите избежать его использования, если вы действительно не имеете в виду его.

Преобразование a char в int обычно не связано с реинтерпретацией.

static_cast<int>(some_char) обновит char до int и получит соответствующее значение.


Однако при определенных обстоятельствах я нахожу static_cast слишком мощным. Он может выполнять небезопасные преобразования указателей и рассчитывает как явное преобразование.

Оба эти могут маскировать ошибки.

Вы можете написать строгую строчку следующим образом:

template<class T, class U>
T implicit_cast( U&& u ) { return std::forward<U>(u); }

теперь вы можете

std::cout << implicit_cast<int>(v[0]) << std::endl;

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


Что здесь происходит? Ну, std::cout - поток, а потоки обращают внимание на пройденный тип. char печатаются, как если бы они были символами стиля `` a``, а не как маленькие целые числа.

Чтобы обработать a char как маленькое целое число, вам нужно преобразовать его в другой целочисленный тип.

То же самое относится к char*; они рассматриваются как указатели на буферы с нулевым завершением char, такие как "hello world", а не как другие указатели.