Когда reinterpret_cast изменяет биты?

Из стандарта С++:

5.2.10.3

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

Меня обучили на этом сайте, чтобы поверить и повторить это. (Даже если это возможно просто мелочи). A reinterpret_cast от float* до int* разрешено создавать другой битовый шаблон. Единственная гарантия заключается в том, что reinterpret_cast -издание, возвращаемое к float*, приведет к созданию исходного битового рисунка.

Мой вопрос: Это когда-нибудь случается? Существует ли существующая реальная платформа или процессор или компилятор, который на самом деле reinterpret_cast для другого битового шаблона? Если нет, существуют ли ситуации реального мира, где reinterpret_cast имеет какие-либо служебные данные во время выполнения?

Во всем моем опыте с reinterpret_cast, приведение было директивой для компилятора, а не для среды выполнения.

Ответ 1

Я работал на платформах, где char* больше, чем int*, и на платформах, где у них был другой макет, хотя размер был тот же. Ни одна из рассматриваемых машин не является особенно актуальным сегодня (хотя, во-вторых, PDP-10, был одним из наиболее важных машин в период расцвета). Также возможно, что некоторые режимы компиляции на Intel в родной режим (или то, что раньше назывался нативным режимом) "нормализовать" указатели в reinterpret_cast, или даже неявное преобразование, чтобы облегчить сравнение адресов. Также возможно (хотя я этого не видел), что такое преобразования обеспечивают правильное выравнивание, например. конверсия из char* до int* может привести к тому, что 2 младших бита будут равны 0. В практика, однако, сегодня я не думаю, что вы, вероятно, см. a reinterpret_cast внести любые изменения между указателем данных типы. Вопрос более исторический. (Но я не уверен в современные встроенные процессоры. Насколько я понимаю, многие из них являются адресацией слов, и поэтому, если sizeof(int) != sizeof(char), они вероятно, потребуется специальный формат для адресации char.)

Ответ 2

Указатели могут в принципе быть разных размеров. Самый большой указатель, если есть какая-либо разница (без учета указателей элементов, говорящих о реальных указателях), char*, так как a char по определению является байтом и может быть где угодно, без выравнивания. void* должен иметь возможность представлять char*.

В системе с int*, использующей меньшее количество бит, чем char*, повторное интерпретирование в этом направлении может быть немного рискованным.

Я думаю, что с этими указателями (хе) вы можете найти это в стандарте. Требование о void* достаточно велико для любого указателя, а также о выравнивании: более строгая/большая, чем меньше бит, необходимых для указателя на этот тип. Но я никогда не слышал о какой-либо существующей системе, где есть такая разница.


Стандартные относительно void* могут представлять char*:

С++ 11 §3.9.2/4:

"
Можно использовать указатель на cv-квалификацию (3.9.3) или cv-unqualified voidуказывать на объекты неизвестного типа. Такой указатель должен иметь возможность удерживать любой объект указатель. Объект типа cv void* должен иметь одинаковый представления и выравнивания, как cv char*

"Любой указатель объекта" подразумевает смутно, что существуют разные размеры указателя.


Standareese относительно выравнивания референта:

С++ 11 §5.2.10/7:

"
Указатель объекта может быть явно преобразован в указатель объекта другого типа. Когда prvalue v типа" указатель на T1 "преобразуется в тип" указатель на cv T2 ", результат is static_cast< cv T2*>(static_cast< cv void*>(v)), если оба T1 и T2 > являются стандартными типами макетов (3.9) и выравниванием требования T2 не более строгие, чем теги T1, или если любой тип void. Преобразование prvalue типа" указатель на T1 "на тип" указатель на T2" (где T1 и T2 - это типы объектов и где выравнивание требования T2 не более строгие, чем требования T1) и обратно к исходному типу дают исходный указатель стоимость. Результат любого другого такого преобразования указателя не указан.

Стоит отметить, что позже в стандарте есть некоторая поддержка эмуляции класса класса деривации класса, которая, по-видимому, противоречит "любому другому" в конце выше:

С++ 11 §9.2/20,

"
Указатель на объект структуры стандартного макета, соответствующим образом преобразованный с помощью reinterpret_cast, указывает на его начальный член (или если этот элемент является битовым полем, а затем блоку, в котором он находится) и наоборот.

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