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