Учитывая один ограничительный указатель на основе другого, они никогда не должны псевдоним? - PullRequest
4 голосов
/ 13 января 2020

Насколько я понимаю, формальное определение "restrict" в разделе 6.7.3.1 C стандарта , в функции ниже указатель y основан на указателе restrict x; следовательно, компилятор будет предполагать, что обращения *x и *y могут иметь псевдоним:

void assign1(int *pA, long N) {
  int *restrict x = pA;
  { 
    int *y = x + N;
    *x = *y;
  }
}

Однако, что если само y объявлено restrict: может ли компилятор предположить, что *x и *y никогда не будет псевдонимом?

void assign2(int *pA, long N) {
  int *restrict x = pA;
  { 
    int *restrict y = x + N;
    *x = *y;
  }     
}

1 Ответ

0 голосов
/ 27 февраля 2020

Цитирование Jeroen Dobbelaere , разработчика LLVM, работающего над «ограниченной» реализацией:

Это определено в 6.7.3.1 параграфе 4 :

... У каждого другого lvalue, используемого для доступа к значению X, также должен быть свой адрес, основанный на P ...

Для assign1:

  • x является ограничительным указателем и предполагается, что он указывает на свой собственный набор объектов
  • y является обычным указателем, основанным на x
  • всем доступе к набору объектов, обозначенных x, выполняются через указатель на основе x

для assign2:

  • x является ограничительным указателем и предполагается, что указатель на собственный набор объектов
  • y также является ограничительным указателем, основанным на x, но предполагается, что он указывает на собственный набор объектов для области действия y
  • из-за этого *x и *y никогда не должны перекрываться, так как все обращения к объектам y должны выполняться на основе указателя, полученного из * 104 4 *

Таким образом, N = 0 вызовет неопределенное поведение в assign2

. При назначении *x вне внутреннего блока код снова становится действительным:

void assign3(int *pA, long N) {
  int *restrict x = pA;
  int tmp;
  {
    int *restrict y = x + N;
    tmp = *y;
  }
  *x = tmp; // may alias with *y
}
...