Путаница с неопределенным поведением для квалификатора ограничения

Я видел следующий пример на cppreference.

void f(int n, int * restrict p, int * restrict q)
{
    while(n-- > 0)
        *p++ = *q++; // none of the objects modified through *p is the same
                     // as any of the objects read through *q
                     // compiler free to optimize, vectorize, page map, etc.
}
void g(void)
{
    extern int d[100];
    f(50, d + 50, d); // OK
    f(50, d + 1, d); // Undefined behavior: d[1] is accessed through both p and q in f
}

В этом примере звонить f(50, d + 50, d); можно.

Но я не понимаю, звонить f(50, d + 1, d); является неопределенным поведением. Почему?


person msc    schedule 22.11.2017    source источник
comment
Поскольку доступ к объекту d[1] в функции f осуществляется как через p, так и через q. комментарий говорит об этом.   -  person Eugene Sh.    schedule 22.11.2017
comment
Я не думаю, что ограничение помогает здесь, потому что «время жизни указателя» - это вызов функции, который в любом случае влияет на оба указателя. Применяется нормальное неопределенное поведение   -  person Martin Beckett    schedule 22.11.2017
comment
@MartinBeckett в функции f оба указателя ограничены, но указывают на один и тот же объект в разное время.   -  person Eugene Sh.    schedule 22.11.2017
comment
@ЕвгенийШ. d содержит базовые адреса массива d[0]   -  person msc    schedule 22.11.2017
comment
@rsp Хм Что? d - это массив. d[0] — элемент массива.   -  person Eugene Sh.    schedule 22.11.2017


Ответы (1)


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

В f(50, d + 50, d); p будет использоваться для изменения d[50] до d[99], а q будет использоваться для доступа к d[0] до d[49]. Перекосов нет, так что все нормально.

В f(50, d + 1, d); p будет использоваться для изменения d[1] до d[50], а q будет использоваться для доступа к d[0] до d[49]. Поскольку некоторые элементы (например, d[1]) изменяются через p и считываются через q, это является нарушением квалификатора restrict.

person interjay    schedule 22.11.2017
comment
привет, интерджей, так что это неопределенное поведение, когда вы получаете доступ к объекту через указатель псевдонима или если указатель псевдонима объекта? Ваше утверждение звучит так, как будто это имеет значение только в том случае, если указатель, указывающий на объект, является разыменованным, и что не имеет значения, является ли другой указатель псевдонимом, если он не разыменован? - person Nergal; 29.07.2018
comment
ааа, так что если бы у меня был другой псевдоним указателя с ограниченным указателем, просто чтобы сохранить адрес, а затем восстановить его обратно к указателю с ограниченным доступом, это не неопределенное поведение? Причина вопроса в том, что я работаю над виртуальной машиной стека, и указатель инструкций ограничен, но код операции должен сохранять значение указателя инструкций в стеке. Я волновался, что это вызовет UB. - person Nergal; 30.07.2018