Вызов функции с ограниченными аргументами, которые уже ограничены в текущей области

Мне трудно понять, что означает restrict с точки зрения вызова функций с уже ограниченными переменными.

Википедия говорит мне:

Ключевое слово limited — это заявление о намерениях, данное программистом компилятору. В нем говорится, что в течение всего времени существования указателя только он или значение, непосредственно полученное из него (например, указатель + 1), будет использоваться для доступа к объекту, на который он указывает.

У меня есть эти три примера функций:

void a(int const *p1, int const *p2) {
    ...
}

void b(int *restrict p1, int *restrict p2) {
    ...
}

void c(int *p1, int *p2) {
    ...
}

и я бы назвал их каждый из функции

foo(int *restrict p1, int *restrict p2) {
    a(p1, p2);
    b(p1, p2);
    c(p1, p1+1);
}

кто из них сдержит restrict обещание, данное объявлением функции foo?

Три случая будут:

  1. Функция a ничего не изменяет, так что это, безусловно, верно.

  2. Как насчет b, его параметры "непосредственно получены" из указателей foo? Нарушу ли я обещание, данное в foo декларации, если я изменю p1 или p2 в b?

  3. Изменится ли ситуация в c по сравнению с предыдущим сценарием, если параметры никак не ограничиваются, и я редактирую например п2 в c?


person Vuoristoneuvos    schedule 15.02.2015    source источник


Ответы (1)


Вот обещания, которые вы даете:

void foo(int *restrict p1, int *restrict p2) {
    // a() can't modify p1[...] or p2[...]
    a(p1, p2);
    // b() CAN modify p1[...] or p2[...]
    // Note that you are still making this promise if you don't use
    // "restrict" in the declaration of b()
    b(p1, p2);
    // c() CAN modify p1[...] but not p2[...]
    c(p1, p1+1);
}

Вы не можете быть уверены, что обещания, которые вы даете, верны, если вы не знаете, что делают функции и как они вызываются.

Например, это неправильно:

int global;
void a(int const *p1, int const *p2) {
    // Since p1 == &global, we can break the promise here
    // by accessing *p1 through the name "global"...
    // Even though this function is perfectly okay by itself!
    global = 5;
}
void foo(int *restrict p1, int *restrict p2) {
    // We have a promise that a() won't modify p1[...]
    // BECAUSE: "restrict" promises that all p1 modifications
    // go through p1, since p1 is passed "const" a() is not
    // supposed to modify *p1, but p1 = &global, and a() modifies
    // global... BOOM!
    // Even though this function is perfectly okay by itself...
    a(p1, p2);
}
int main() {
    int y;
    // Illegal!  Once you pass &global to foo(), BOOM!
    foo(&global, &y);
}

Вот почему restrict немного сложнее. Вы не можете понять, правильно это или нет, основываясь только на сигнатурах функций.

person Dietrich Epp    schedule 17.02.2015
comment
Спасибо за ваш ответ. И причина, по которой я могу изменить p1 или p2 в b(), заключается в том, что они являются производными от p1 и p2 в foo() (мне действительно нужно было выбрать разные переменные...), верно? - person Vuoristoneuvos; 17.02.2015
comment
И чтобы уточнить, причина, по которой я могу безопасно использовать как p1, так и p2 в c(), не вызывая неопределенного поведения, заключается в том, что они оба являются производными от p1 в foo(). - person Vuoristoneuvos; 17.02.2015
comment
Да, вы можете изменить *p1 и *p2 в b() и c(), поскольку они являются производными от p1 и p2 в foo(). Однако вы не можете (например) изменить p1[1] в c(), а затем прочитать из p2[0], потому что они находятся по одному и тому же адресу, а внутри c() вы обещали, что не будете этого делать. - person Dietrich Epp; 18.02.2015