Страницы

Поиск по вопросам

понедельник, 23 декабря 2019 г.

И снова о доступе к объектам через указатели на char

#cpp #language_lawyer


Вопрос 1.

В стандарте языка есть такое понятие как similar types (conv.qual/2). Являются ли
типы unsigned char и int similar? (Я полагаю, что нет, однако, если да, то хотелось
бы узнать почему?)

Вопрос 2.

В разделе стандарта языка, описывающего аддитивные операции (в частности арифметику
указателей), есть интересный пункт expr.add/6:


  For addition or subtraction, if the expressions P or Q have type “pointer to cv
T”, where T and the array element type are not similar, the behavior is undefined.
[ Note: In particular, a pointer to a base class cannot be used for pointer arithmetic
when the array contains objects of a derived class type. — end note ]


Пусть есть следующий код:

int mass[2];
unsigned char *p = reinterpret_cast(mass);

p = p + 1;  //UB?


Является ли приведённый код неопределённым поведением? Если нет, то почему?  

(По-моему, приведённый код в точности соответствует приведённой цитате из стандарта.
Этот вопрос возник у меня отчасти потому, что когда речь заходит о strict aliasing
rules, то всегда оговаривается, что к объектам можно получить доступ через char/unsigned
char. Но о каком доступе к объекту может идти речь, если нельзя наращивать указатель?)

Вопрос 3.

Если поведение кода в вопросе 2 не определено, то как реализовать свой memcpy?
    


Ответы

Ответ 1



Речь в [conv.qual] идёт о разложении сложных типов, являющихся указателями или массивами с перемежающими квалификаторами const, volatile. Причём наличие условия n > 0 говорит о том, что эти типы должны быть как минимум второго уровня, условно, указатель на указатель. При всём этом базовый тип U в разложении должен быть одинаковым. Понятно, что базовые типы int и unsigned char таковыми не являются. Немного примеров схожих (similar) и не схожих типов можно посмотреть здесь (раздел Type aliasing). Далее в цитате, которую Вы приводите, упоминается пример, говорящий, что нельзя итерироваться по контейнеру элементов производного типа, имея указатель на базовый тип: struct B {}; struct D : B {}; D a[10]; B* p = a; p++; // породит значение, которое может не указывать на валидный объект типа D Доступ же к объектам через указатель на char, unsigned char или std::byte явно разрешен. То есть проблем с реализацией memcpy не будет.

Комментариев нет:

Отправить комментарий