Кастинг между указателями примитивного типа

Является ли следующее четко определенным:

char* charPtr = new char[42];
int* intPtr = (int*)charPtr;

charPtr++;
intPtr = (int*) charPtr;

intPtr неправильно выровнен (по крайней мере, в одном из двух случаев). Это незаконно просто иметь это там? Это UB, использующий это на любой стадии? Как вы можете использовать это и как вы не можете?

5

Решение

Во-первых, конечно: указатель гарантированно выровнен в
первый случай (согласно §5.3.4 / 10 и §3.7.4.1 / 2), и может быть правильно
выравнивается в обоих случаях. (Очевидно, если sizeof(int) == 1, но
даже если это не так, реализация не
обязательно есть требования по выравниванию.)

И чтобы было ясно: все ваши броски reinterpret_cast,

Кроме того, это интересный вопрос, потому что, насколько
Я могу сказать, что нет никакой разницы в двух бросках, насколько
Стандарт касается. Результаты преобразования
не указано (согласно §5.2.10 / 7); ты даже не гарантирован
что превращает его обратно в char* приведет к
первоначальная стоимость (Это явно не будет, например, на машинах
где int* меньше чем char*.)

На практике, конечно: стандарт требует возврата
ценность new char[N] быть достаточно выровненным для любого значения
что может вписаться в него, так что вы гарантированно сможете сделать:

intPtr = new (charPtr) int;

Который имеет тот же эффект, что и ваш актерский состав, учитывая, что
конструктор по умолчанию для int это неоперация. (И при условии, что
sizeof(int) <= 42.) Так что сложно представить реализацию
в котором первая часть терпит неудачу. Вы должны быть в состоянии использовать
intPtr как и любой другой законно полученный intPtr, И
Идея, что преобразование его обратно в char* каким-то образом приведет
в другом значении от оригинала char* кажется
нелепа.

Во второй части все ставки сняты: вы определенно не можете
разыменовывать указатель (если ваша реализация не гарантирует
в противном случае), и вполне возможно, что преобразовать его обратно
в char* приводит к чему-то другому. (Представь себе слово
адрес машины, например, где преобразование char* для
int* округляет вверх. Тогда обратное преобразование приведет к
char* который был sizeof(int) выше, чем оригинал. Или же
где всегда приводилась попытка конвертировать смещенный указатель
в нулевом указателе.)

1

Другие решения

Как правило, результат не определен (5.2.10p7), если требования к выравниванию int больше, чем у char, которым они обычно будут. Результатом будет действительное значение типа int * так может быть, например, печатается как указатель с operator<< или преобразован в intptr_t,

Поскольку у результата есть неопределенное значение, если это не определено реализацией, поведение не определено для его косвенного выполнения и выполнения преобразования lvalue в rvalue для результирующего int lvalue (за исключением неоцененных контекстов). Преобразование обратно в char * не обязательно туда-обратно.

Однако, если оригинал char * сам был результатом броска из int *затем актерский состав int * считается второй половиной поездки туда и обратно; в этом случае приведение определено.

В частности, в случае выше, где char * был результатом new[] выражение, мы гарантируем (5.3.4p10), что char * указатель соответствующим образом выровнен для int, пока sizeof(int) <= 42, Поскольку new[] выражение получает свое хранилище из функции выделения, применяется 3.7.4.1p2; void * указатель может быть преобразован
указатель любого полного типа объекта с фундаментальным требованием выравнивания, а затем используется для доступа к объекту […]
что, наряду с примечанием к 5.3.4p10, влечет за собой char * указатель, возвращаемый new[] выражение. В этом случае int * указатель на неинициализированный int объект, поэтому выполнение преобразования lvalue в rvalue для его косвенности не определено (3.8p6), но назначение его косвенности полностью определено. int объект в хранилище выделено (3.7.4.1p2), поэтому преобразование int * вернуться к char * даст исходное значение за 1.8p6. Это не относится к увеличенному char * указатель как если sizeof(int) == 1 это не адрес int объект.

3

По вопросам рекламы [email protected]