Этот вопрос следует этому предыдущему вопросу об определенности memcpy(0, 0, 0)
, который был окончательно определен как поведение undefined.
Как показывает связанный вопрос, ответ зависит от содержания предложения C11 7.1.4: 1
Каждое из следующих утверждений применяется, если явно не указано иное в следующих подробных описаниях: Если аргумент функции имеет недопустимое значение (например, значение вне домена функции или указатель вне адресного пространства программа или нулевой указатель [...]) [...] поведение undefined. [...]
Стандартная функция memcpy()
ожидает указателей на void
и const void
, так как:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
Вопрос стоит задать вовсе не потому, что в стандарте есть два понятия "правильные" указатели: есть указатели, которые могут быть достоверно получены с помощью арифметики указателя и могут быть справедливо сопоставлены с <
, >
другим указателям внутри одного и того же объекта. И есть указатели, которые действительны для разыменования. Первый класс включает в себя "одно-прошлое" указатели, такие как &a + 1
и &b + 1
в следующем фрагменте, тогда как последний класс не включает их как действительные.
char a;
const char b = '7';
memcpy(&a + 1, &b + 1, 0);
Если приведенный выше фрагмент считается определенным поведением, в свете того факта, что аргументы memcpy()
в любом случае набираются как указатели на void
, поэтому вопрос об их соответствующих действиях не может быть о разыменовании их. Или следует считать &a + 1
и &b + 1
"вне адресного пространства программы"?
Это имеет значение для меня, потому что я в процессе формализации эффектов стандартных функций C. Я написал одно предварительное условие memcpy()
как requires \valid(s1+(0 .. n-1));
, пока не было указано на мое внимание, что GCC 4.9 начал агрессивно оптимизируйте вызовы функций библиотеки за пределами того, что выражено в приведенной выше формуле (действительно). Формула \valid(s1+(0 .. n-1))
в этом конкретном языке спецификации эквивалентна true
, когда n
является 0
, и не фиксирует поведение undefined, которое GCC 4.9 полагается для оптимизации.