Я нахожусь в середине обсуждения, пытаясь выяснить, допустим ли недопустимый доступ в С++ через reinterpret_cast
. Я думаю, что нет, но мне трудно найти правильную часть (-ы) стандарта, которые подтверждают или опровергают это. Я смотрел на С++ 11, но я был бы в порядке с другой версией, если это более понятно.
Несвязанный доступ undefined в C11. Соответствующая часть стандарта C11 (п. 6.3.2.3, пункт 7):
Указатель на тип объекта может быть преобразован в указатель на другой тип объекта. Если результирующий указатель неправильно выровнен для ссылочного типа, поведение undefined.
Поскольку поведение неприсоединенного доступа undefined, некоторые компиляторы (по крайней мере, GCC) принимают это за то, что это нормально, чтобы генерировать инструкции, которые требуют согласованных данных. В большинстве случаев код по-прежнему работает для неуравновешенных данных, потому что большинство команд x86 и ARM в наши дни работают с неуравновешенными данными, но некоторые из них этого не делают. В частности, некоторые векторные инструкции этого не делают, а это значит, что по мере того, как компилятор лучше справляется с созданием оптимизированных инструкций, код, который работал со старыми версиями компилятора, может не работать с более новыми версиями. И, конечно же, некоторые архитектуры (как MIPS) не работают с неуравновешенными данными.
С++ 11, конечно, сложнее. § 5.2.10, пункт 7 гласит:
Указатель объекта может быть явно преобразован в указатель объекта другого типа. Когда prvalue
v
типа "указатель наT1
" преобразуется в тип "указатель на cvT2
", результатstatic_cast<cv T2*>(static_cast<cv void*>(v))
, если обаT1
иT2
являются стандартными типами макета ( 3.9), а требования к выравниваниюT2
не более строгие, чем требования дляT1
, или если любой типvoid
. Преобразование prvalue типа "указатель наT1
" в тип "указатель наT2
" (гдеT1
иT2
являются типами объектов и где требования к выравниваниюT2
не более строгие, чем требованияT1
) и обратно к исходному типу дает исходное значение указателя. Результат любого другого такого преобразования указателя не указан.
Обратите внимание, что последнее слово "неуказано", а не "undefined". В § 1.3.25 определяется "неуказанное поведение" как:
для хорошо сформированной программы и правильных данных, которая зависит от реализации
[Примечание. Реализация не требуется для документирования поведения. Диапазон возможных видов поведения обычно определяется в этом международном стандарте. - конечная нота]
Если я что-то не упустил, стандарт в действительности не ограничивает диапазон возможных поведений, что, по-видимому, указывает на то, что очень разумным поведением является то, что реализовано для C (по крайней мере, GCC): не поддерживает их. Это означало бы, что компилятор свободен предположить, что неприглаженные обращения не происходят и выдают инструкции, которые могут не работать с неизмененной памятью, как и для C.
Человек, с которым я обсуждаю это, однако, имеет другую интерпретацию. Они ссылаются на § 1.9, параграф 5:
Соответствующая реализация, выполняющая хорошо сформированную программу, должна обеспечивать такое же наблюдаемое поведение, как и одно из возможных исполнений соответствующего экземпляра абстрактной машины с той же программой и тем же самым вводом. Однако, если какое-либо такое исполнение содержит операцию undefined, этот международный стандарт не требует от реализации выполнения этой программы с этим вводом (даже в отношении операций, предшествующих первой операции undefined).
Так как не существует поведения undefined, они утверждают, что компилятор С++ не имеет права предполагать, что неприсоединенный доступ не возникает.
Итак, являются ли невыполненные обращения через reinterpret_cast
безопасными в С++? Где говорится в спецификации (любая версия)?
Изменить. Под "доступом" я подразумеваю загрузку и хранение. Что-то вроде
void unaligned_cp(void* a, void* b) {
*reinterpret_cast<volatile uint32_t*>(a) =
*reinterpret_cast<volatile uint32_t*>(b);
}
Как выделяется память, фактически вне моей области (это для библиотеки, которую можно вызывать с данными из любого места), но malloc
и массив в стеке являются вероятными кандидатами. Я не хочу устанавливать какие-либо ограничения на выделение памяти.
Изменить 2. Просьба привести источники (например, стандарт, раздел и параграф С++) в ответах.