Запутался в квалификаторе ограничения C

Во-первых, cppreference говорит об ограничении следующее:

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

Но под этим абзацем написано:

Ограниченные указатели могут свободно назначаться неограниченным указателям, возможности оптимизации сохраняются до тех пор, пока компилятор может анализировать код:

void f(int n, float * restrict r, float * restrict s) {
   float * p = r, * q = s; // OK
   while(n-- > 0) *p++ = *q++; // almost certainly optimized just like *r++ = *s++
}

В приведенном выше примере r[0] является объектом, доступным через ограниченный указатель r, и доступ к нему осуществляется через p, что, кажется, противоречит первому абзацу (что доступ к r[0] должен осуществляться исключительно через r)?

Второй:

Присвоение одного ограниченного указателя другому является неопределенным поведением, за исключением случаев, когда присваивается указатель на объект в некотором внешнем блоке указателю в некотором внутреннем блоке (включая использование аргумента ограниченного указателя при вызове функции с ограниченным параметром указателя) или когда возврат из функции (и в противном случае, когда блок указателя from закончился).

Итак, подходит ли следующий код?

void foo(char* restrict a, size_t s)
{
    for(char* restrict aa = a; aa < a + s; ++aa) // Is aa in an inner block?
    {
        *aa = '\0';
    }
}

person user2711115    schedule 14.03.2017    source источник
comment
Ваш код никогда не разыменовывает указатели?   -  person Kerrek SB    schedule 14.03.2017
comment
Дело было в том, чтобы узнать, было ли присваивание aa = a неопределенным поведением в соответствии с приведенным выше определением, но я отредактировал его.   -  person user2711115    schedule 14.03.2017
comment
проверьте ответ 2   -  person jjm    schedule 14.03.2017
comment
Цикл for номинально представляет собой блок вокруг цикла while, так что все должно быть в порядке.   -  person Kerrek SB    schedule 14.03.2017
comment
restrict — это просто договор между программистом и компилятором. Обнаружив restrict квалифицированные указатели в качестве параметров функции, программист должен пообещать компилятору, что он не будет передавать этой функции два параметра, которые перекрываются в памяти. Если компилятор может предположить это, ему не нужно будет включать дополнительный служебный код для обработки перекрытий. Но ничто не заставляет компилятор давать диагностику, если программист нарушает этот контракт. Вот как это происходит, когда в комитете по стандарту C присутствует слишком много компиляторов...   -  person Lundin    schedule 14.03.2017


Ответы (1)


Ключевым моментом в примере 1 является то, что lvalue *p, используемое для доступа к базовому массиву, на который указывает r, имеет адрес, основанный на r. Иными словами, это косвенный доступ через r. Так как *q также имеет свой адрес, основанный на s, все обращения происходят, даже если косвенно, через исходные ограниченные указатели: здесь нет UB.

Пример 2 еще более тривиален. Вы объявляете новый ограниченный указатель, основанный на исходном. Так что УБ тоже нет. Но в примере 2 оба ограниченных квалификатора не добавляют никакого значения, потому что внутри блока (определение функции foo) используется только один единственный указатель, поскольку aa основан на a.

В примере 1 квалификаторы restrict объявляют компилятору, что массивы, на которые указывают r и s, не перекрываются: доступ через r (прямо или косвенно через p) не должен касаться массива, на который указывает s.

person Serge Ballesta    schedule 14.03.2017
comment
Спасибо, у меня было несколько смутное представление о том, что означает прямой/непрямой доступ, и это хорошо прояснило! - person user2711115; 14.03.2017
comment
По мере того, как я читал об этом больше, я наткнулся на эту статью (специально ориентированную на TI) processors.wiki.ti.com/images/f/ff/ Если вы посмотрите на раздел 3.5 на стр. 18, он явно противоречит cppreference и тому, что вы только что сказали о примере 1. Am Я правильно предполагаю, что компилятор TI не соответствует стандарту? - person user2711115; 14.03.2017