Пытаюсь понять, в какой мере strict aliasing rule
не касается char
.
Во многих источниках делается акцент на том, что char
может накладываться на любой тип, но не наоборот. Что это значит?
Допустим:
int i;
int *pi = &i;
char *pc = (char*)&i;
// Первый случай.
*pc = 0;
*pi = 1;
// *pc != 0?
// Второй случай.
*pi = 0;
*pc = 1;
// *pi != 0?
Исключим из рассмотрения порядок байтов, требования выравнивания и прочие штуки.
Верно ли я понимаю, что в связи с однонаправленностью описанного правила, один из описанных случаев будет корректен, а другой - вызовет неопределенное поведение?
Или же правило описывает иную ситуацию, и оба приведенных случая не выльются в неопределенное поведение?
Идентично ли поведение C
и C++
?
Я совершенно запутался с этим sa
...
Во-первых что такое "strict aliasing" (в двух словах) - это следствие из ограниченности перечня типов выражений, для которых в стандарте определяется поведение при обращение к объекту определенного типа. Это следствие заключается в том, что у компилятора появляется возможность считать, что указатели (и ссылки) несовместных типов никогда не указывают на одно и то же место в памяти, то бишь что они не являются алиасами одного и того же объекта.
Более формально этот перечень определен так:
8.2 Properties of expressions [expr.prop]
11 If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined: 63
(11.1) — the dynamic type of the object,
(11.2) — a cv-qualified version of the dynamic type of the object,
(11.3) — a type similar (as defined in 7.5) to the dynamic type of the object,
(11.4) — a type that is the signed or unsigned type corresponding to the dynamic type of the object,
(11.5) — a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
(11.6) — an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
(11.7) — a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
(11.8) — a char, unsigned char, or std::byte type.
Что же особенного в char
? Дело в том, что модель памяти основана на адресации байт и все объекты в языке имеют байтовое представление. Последний пункт в перечне как раз разрешает получение доступа к байтовому представлению (object representation).
Однако заметьте, что эти правила относятся непосредственно к доступу к объекту, то бишь левой части выражения *pc = 0;
. А само присваивание работает потому что для тривиально-копируемых объектов разрешено копирование байт туда-сюда.
Далее, приведенный в вопросе "второй случай" на самом деле ничем не отличается от первого. Обратный пример тут должен был бы выглядеть вот так:
alignas(int) char bytes[sizeof(int)]{};
char * pc{static_cast<char *>(bytes)};
int * pi{reinterpret_cast<int *>(pc)};
*pi = 1; // неопределенное поведение!
Но это еще не все, дело в том, что в имеется возможность размещать объекты в памяти (provide storage)!
alignas(int) char bytes[sizeof(int)]{};
char * pc{static_cast<char *>(bytes)};
int * pi1{new(pc) int{}};
*pi1 = 1; // определенное поведение!
int * pi2{reinterpret_cast<int *>(pc)};
*pi2 = 1; // (внезапно) по-прежнему неопределенное поведение, хотя pi2 == pi1!
Виртуальный выделенный сервер (VDS) становится отличным выбором
собственно вопрос в шапке: Как задать имя конкретно для кнопки "Show details", с другими кнопками проблем нет