Предположим, у нас есть объявление функции, для которого у нас нет доступа к ее определению:
void f(int * restrict p, int * restrict q, int * restrict r);
Поскольку мы не знаем, как будет осуществляться доступ к указателям, мы не можем знать, вызовет ли вызов неопределенное поведение или нет, даже если мы передаем один и тот же указатель, как показано в примере 6.7.3.1.10:
Объявления параметров функции:
void h(int n, int * restrict p, int * restrict q, int * restrict r) { int i; for (i = 0; i < n; i++) p[i] = q[i] + r[i]; }
проиллюстрируйте, как немодифицированный объект может иметь псевдоним с помощью двух ограниченных указателей. В частности, если
a
иb
являются непересекающимися массивами, вызов формыh(100, a, b, b)
имеет определенное поведение, поскольку массивb
не изменяется внутри функцииh
.
Следовательно, является ли restrict
излишним в этих случаях, кроме как подсказкой/аннотацией для вызывающих, если мы не знаем что-то еще о функции?
Например, возьмем sprintf
(7.21.6.6) из стандартной библиотеки:
Краткий обзор
#include <stdio.h> int sprintf(char * restrict s, const char * restrict format, ...);
Описание
Функция
sprintf
эквивалентнаfprintf
, за исключением того, что вывод записывается в массив (указанный аргументомs
), а не в поток. (...)
Из синопсиса и первого предложения описания мы знаем, что s
будет записано и что s
является ограниченным указателем. Следовательно, можем ли мы уже предположить (не читая дальше), что вызов типа:
char s[4];
sprintf(s, "%s", s);
вызовет неопределенное поведение?
- #P12# <блочная цитата> #P13# блочная цитата>
Если нет, то наоборот: является ли квалификатор
restrict
излишним, поскольку именно описание дает нам знать, какое поведение будет undefined?