0

I have trouble understanding what restrict means in terms with calling functions with already restricted variables.

Wikipedia tells me:

The restrict keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only it or a value directly derived from it (such as pointer + 1) will be used to access the object to which it points.

I have these three example functions:

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

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

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

and I would call them each from a function

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

which of them would keep the restrict promise that function foo declaration makes?

The three cases would be:

  1. Function a doesn't modify anything, so that would surely hold.

  2. How about b, are the parameters to it "directly derived" from the foo's pointers? Am I braking the promise I'm giving in foo declaration if I modify the p1 or p2 in b?

  3. Does the situation change in c from the previous scenario if the parameters aren't restricted in any way, and I edit for example p2 in c?

1 Answers1

0

Here are the promises you are making:

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);
}

You can't be sure that the promises you are making are correct unless you know what the functions do and how they are called.

For example, this is wrong:

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);
}

This is why restrict is a bit tricky. You can't figure out if it is correct or not based on the function signatures alone.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Thank you for your answer. And the reason I can modify `p1` or `p2` in `b()` is that they are derived from `p1` and `p2` in `foo()` (I really should have picked different variables...), correct? – Vuoristoneuvos Feb 17 '15 at 19:09
  • And to clarify, the reason I can safely use both `p1` and `p2` in `c()` without causing undefined behaviour is because they both are derived from `p1` in `foo()`. – Vuoristoneuvos Feb 17 '15 at 19:16
  • Yes, you can modify `*p1` and `*p2` in `b()` and `c()` because they are derived from `p1` and `p2` in `foo()`. However, you can't (for example) modify `p1[1]` in `c()` and then read from `p2[0]`, because those are at the same address, and within `c()`, you've promised that you won't do that. – Dietrich Epp Feb 17 '15 at 21:18