Определена ли инициализация указателя с произвольным литеральным ненулевым значением? - PullRequest
0 голосов
/ 27 мая 2018

Рассмотрим:

struct T{};

int main() {
    T* p = (T*)0xDEADBEEF;
}

Использование недопустимого указателя определяется реализацией .Разыменование это неопределенное поведение .Мой вопрос не о них.

Мой вопрос заключается в том, определена ли простая инициализация p как есть.

Если вы думаете,у вас уже есть вся информация, необходимая для ответа на этот вопрос (или если вы узнали, что это дубликат), вам больше не нужно читать .Ниже приведены некоторые бормотания, основанные на моих выводах:

Стандарт C (на котором основан стандарт C ++) гласит:

6.3.2.3 Указатели

5 Целое число может быть преобразовано в любой тип указателя.За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть представлением прерывания.

Какие подсказки могут бытьРеализация определена.

Стандарт C ++ только определяет (насколько мне известно), что любое использование неверного значения указателя определяется реализацией.Сноска имеет особое значение, поскольку, как представляется, она предполагает, что простая копия такого значения уже используется указателем.(Или это означает указанное значение? Я в замешательстве)

6.7 Срок хранения

4 Когда заканчивается срок действия регионахранения, значения всех указателей, представляющих адрес любой части этой области хранения, становятся недействительными значениями указателя (6.9.2).Направление через недопустимое значение указателя и передача недопустимого значения указателя в функцию освобождения имеют неопределенное поведение.Любое другое использование недопустимого значения указателя имеет поведение, определяемое реализацией. 37

37 Некоторые реализации могут определять, что копирование недопустимого значения указателя вызывает системную ошибку времени выполнения

Этот вид соответствует стандарту C.Проблема в том, что я не уверен, что это пример недопустимого значения указателя , так как в стандарте четко сказано, что этот тип значения вызван окончанием срока хранения для этого достигнутого адреса (которыйявно никогда не случалось).

Есть также много экземпляров арифметики указателей, которые Неопределенное поведение TM , ноздесь явно не делается арифметика или манипуляции со значением указателя.Это просто инициализация.

Ответы [ 2 ]

0 голосов
/ 27 мая 2018

Ваш каст в стиле C исполняет reinterpret_cast;приведение к произвольному целочисленному значению, как это, определяется реализацией :

8.5.1.10 Переинтерпретация приведения

5 Значение целого типаили тип перечисления может быть явно преобразован в указатель.Указатель, преобразованный в целое число достаточного размера (если таковое существует в реализации) и обратно в тот же тип указателя, будет иметь свое первоначальное значение;Отображения между указателями и целыми числами определяются реализацией.[ Примечание: За исключением случаев, описанных в [basic.stc.dynamic.safety] , результатом такого преобразования не будет безопасно полученное значение указателя. - примечание к концу ]

Если результат (как считается реализацией) является недопустимым значением указателя, то он, вероятно, снова определяется реализацией чтопроисходит, когда она хранится в переменной, но это менее понятно:

6.6.4 Продолжительность хранения

4 Когда заканчивается конец регионахранения, значения всех указателей, представляющих адрес любой части этой области хранения, становятся недопустимыми указателями .Направление через недопустимое значение указателя и передача недопустимого значения указателя в функцию освобождения имеют неопределенное поведение.Любое другое использование недопустимого значения указателя имеет поведение, определяемое реализацией.

0 голосов
/ 27 мая 2018

Исходя из моего опыта работы с настольными (UNIX, Linux, Windows) приложениями, я думаю, что вы можете назначить любое значение указателю.Если вы не разыменовываете указатель, эти системы не вызывают странного поведения, когда вы присваиваете такие значения указателю.

В следующем примере показан один механизм, который я видел, когда дело доходит до сохранения указателей на диск и восстановленияуказатели с диска.

Давайте взглянем упрощенно на связи между гранями, ребрами и вершинами модели САПР.

struct Face;
struct Edge;
struct Vertex;

struct Face
{
   std::vector<Edge*> edges;
};

struct Edge
{
   std::vector<Face*> faces;
   Vertex* start;
   Vertex* end;
};

struct Vertex
{
   std::vector<Edge*> edges;
   double x;
   double y;
   double z;
};

и у вас будет грань в плоскости XY.

       E3
V4 +--------+ V3
   |        |
E4 |    F   | E2
   |        |
   +--------+
 V1     E1   V2

Такое лицо может быть сохранено на диск в следующем формате:

0 Face 4 $1 $2 $3 $4
1 Edge 1 $0 $5 $6
2 Edge 1 $0 $6 $7 
3 Edge 1 $0 $7 $8
4 Edge 1 $0 $8 $5
5 Vertex 2 $1 $4 0 0 0 
6 Vertex 2 $2 $1 10 0 0 
7 Vertex 2 $3 $2 10 10 0 
8 Vertex 2 $4 $3 0 10 0 

, где первое число указывает индекс в массиве объектов, в то время как поля, имеющие $префикс - это указатель на элемент с этим индексом.

Когда эта информация читается с диска, существует два прохода, чтобы восстановить объекты в пригодное для использования состояние.При первом проходе индексы хранятся вместо указателей.Во втором проходе индексы конвертируются в указатели.На первом проходе числа [0 - 8] сохраняются там, где ожидаются указатели.Только после второго прохода указатели будут указывать на соответствующие объекты.

Длинная история сортировки, переменным-членам указателя присваиваются значения, которые, очевидно, не являются допустимыми указателями, но механизм работает безупречно.

это было бы проблемой для других платформ, я не могу комментировать.У меня нет опыта, чтобы отступить.

...