Подтвердить что ты не робот

Являются ли сопоставления в указателях за пределами диапазона четко определенными?

С учетом следующего кода:

char buffer[1024];
char * const begin = buffer;
char * const end = buffer + 1024;
char *p = begin + 2000;
if (p < begin || p > end)
    std::cout << "pointer is out of range\n";

Хорошо ли определены сравнения (p < begin и p > end)? Или этот код имеет поведение undefined, потому что указатель был расширен за конец массива?

Если сравнения хорошо определены, что такое определение?

(дополнительный кредит: оценка самого begin + 2000 поведения undefined?)

4b9b3361

Ответ 1

Оценка begin+2000 равна undefined, она проходит мимо конца массива - вы можете перейти к концу, но не дальше.

Из С++ 11 §5.7/5 Аддитивные операторы:

Когда выражение, которое имеет интегральный тип, добавляется или вычитается из указателя, результат имеет тип операнда указателя. Если операнд указателя указывает на элемент объекта массива, и массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что разность индексов результирующих и исходных элементов массива равна интегральному выражению. [...] Если оба операнда указателя и результат указывают на элементы одного и того же объекта массива или один за последним элементом объекта массива, оценка не должна приводить к переполнению; в противном случае, поведение undefined.

Для сопоставления указателей, которые должны быть указаны, если у вас есть действительные указатели для начала, они по существу должны быть указателями на один и тот же массив (или один за концом) или указатели на нестатические элементы данных одного и того же элемента управления доступом одного и того же объекта (если только это не объединение).

Подробности приведены в §5.9/2 Реляционные операторы:

Указатели на объекты или функции одного и того же типа (после конверсий указателей) можно сравнить с результатом, определяемым следующим образом:

  • Если два указателя p и q того же типа указывают на один и тот же объект или функцию, или оба указывают одно прошлое конец одного и того же массива или оба являются нулевыми, то p <= q и p >= q оба дают true и p < q и p > q обе дают false.
  • Если два указателя p и q того же типа указывают на разные объекты, которые не являются членами одного и того же объект или элементы одного и того же массива или разные функции или если только один из них является нулевым, результаты p < q, p > q, p <= q и p >= q не определены.
  • Если два указателя указывают на нестатические элементы данных одного и того же объекта или на подобъекты или элементы массива таких элементов, рекурсивно, указатель на более поздний объявленный элемент сравнивается больше, если два члена имеют одинаковый контроль доступа (раздел 11) и при условии, что их класс не является объединением.
  • Если два указателя указывают на нестатические элементы данных одного и того же объекта с различным контролем доступа (Пункт 11) результат не указан. - Если два указателя указывают на нестатические элементы данных одного и того же объекта объединения, они сравнивают равные (после преобразование в void *, если необходимо). Если два указателя указывают на элементы одного и того же массива или один за ним конец массива, указатель на объект с более высоким индексом сравнивается выше.
  • Другие сравнения указателей не определены.

Ответ 2

Я предполагаю С++ 11. В соответствии с параграфом 5 раздела 5.7 (аддитивные операнды) поведение *p = begin + 2000 составляет undefined, прежде чем вы даже дойдете до сравнения:

Если оба операнда указателя и результат указывают на элементы тот же объект массива или один за последним элементом объекта массива, оценка не должна приводить к перегрузке; в противном случае поведение не определено.

Ответ 3

Поведение вашей программы undefined, но не из-за сравнения.

Оценка выражения begin + 2000 имеет поведение undefined, потому что результат будет указывать более одного элемента за конец массива 1024 элементов.

Цитата С++ 11 (фактически N3485 черновик), 5.7p4 [expr.add]:

Когда выражение с интегральным типом добавляется или вычитается из указателя результат имеет тип операнда указателя. [...] Если оба операнда указателя и результат указывают на элементы тот же объект массива или один за последним элементом объекта массива, оценка не должна приводить к переполнению; в противном случае поведение undefined.

Короче говоря, просто вычисление указателя out-of-bounds имеет поведение undefined; не имеет значения, какие операции вы выполняете на этом указателе после этого.