Нарушает ли этот код строгое сглаживание?
struct {int x;} a;
*(int*)&a = 3
Говоря более абстрактно, допустимо ли приведение типов между разными типами, если примитивные операции чтения/записи имеют правильный тип?
Нарушает ли этот код строгое сглаживание?
struct {int x;} a;
*(int*)&a = 3
Говоря более абстрактно, допустимо ли приведение типов между разными типами, если примитивные операции чтения/записи имеют правильный тип?
Во-первых, допустимо приведение в C. §6.7.2.1/13:
Внутри структурного объекта члены, не являющиеся битовыми полями, и единицы, в которых находятся битовые поля, имеют адреса, которые увеличиваются в порядке их объявления. Указатель на структурный объект, соответствующим образом преобразованный, указывает на его начальный элемент (или, если этот элемент является битовым полем, то на единицу, в которой он находится), и наоборот. Внутри объекта структуры может быть безымянный отступ, но не в его начале.
Правило псевдонимов выглядит следующим образом (§6.5/7):
Доступ к хранимому значению объекта должен осуществляться только с помощью выражения lvalue, которое имеет один из следующих типов:
- тип, совместимый с эффективным типом объекта,
- квалифицированная версия типа, совместимая с действующим типом объекта,
- тип, который является подписанным или беззнаковым типом, соответствующим эффективному типу объекта,
- тип, который является подписанным или беззнаковым типом, соответствующим уточненной версии эффективного типа объекта,
- тип агрегата или объединения, который включает один из вышеупомянутых типов среди своих членов (включая, рекурсивно, член подагрегата или содержащего объединения), или
- тип персонажа.
Здесь вы будете получать к нему доступ с помощью указателей «типа, совместимого с эффективным типом объекта» и «агрегированного или объединенного типа, который включает один из вышеупомянутых типов среди своих членов», поэтому также нет проблем с псевдонимами. Таким образом, в C действительно совершенно законно обращаться к первому члену структуры путем приведения указателя на структуру к типу рассматриваемого члена.
Однако в C++ вы часто найдете виртуальные таблицы и другие вещи в начале объекта C++. Однако в вашем конкретном случае ваша структура имеет стандартный макет, поэтому это явно разрешено (§9.2/20 в n3290, спасибо Люку Дантону! - С++ 03, по-видимому, имеет аналогичное правило, выраженное в терминах объектов POD) .
reinterpret_cast
указателем на его начальный член (9.2 Члены класса [class.mem], параграф 20 в n3290). Это правило (и все, что связано со стандартными типами макета) предназначено для имитации правил C, которые здесь цитируются. С++ 03 будет иметь аналогичные вещи, за исключением того, что это будет структура POD, а не структура стандартного макета.
- person Luc Danton; 17.03.2012
c++
. ;-] - person ildjarn   schedule 17.03.2012&a.x
. - person Jens Gustedt   schedule 17.03.2012a.x
. :) - person Geoffrey Irving   schedule 17.03.2012reinterpret_cast
. Итак, с точки зрения языкового юриста, этот код не имеет определенного поведения в C++97. Мое замечание не имеет, повторяю, НУЛЕВОЙ актуальности для реального мира. - person curiousguy   schedule 21.07.2012