Function call with pointer to non-const and pointer to const arguments of same address

Willy :

I want to write a function that input an array of data and output another array of data using pointers.

I'm wondering what is the result if both src and dst pointed to the same address because I know compiler can optimize for const. Is it undefined behavior? (I tagged both C and C++ because I'm not sure if the answer may differ between them, and I want to know about both.)

void f(const char *src, char *dst) {
    dst[2] = src[0];
    dst[1] = src[1];
    dst[0] = src[2];
}

int main() {
    char s[] = "123";
    f(s,s);
    printf("%s\n", s);
    return 0;
}

In addition to above question, is this well-defined if I delete the const in original code?

einpoklum :

While it is true that the behavior is well-defined - it is not true that compilers can "optimize for const" in the sense that you mean.

That is, a compiler is not allowed assume that just because a parameter is a const T* ptr, the memory pointed to by ptr will not be changed through another pointer. The pointers don't even have to be equal. The const is an obligation, not a guarantee - an obligation by you (= the function) not to make changes through that pointer.

In order to actually have that guarantee, you need to mark the pointer with the restrict keyword. Thus, if you compile these two functions:

int foo(const int* x, int* y) {
    int result = *x;
    (*y)++;
    return result + *x;
}

int bar(const int* x, int* restrict y) {
    int result = *x;
    (*y)++;
    return result + *x;
}

the foo() function must read twice from x, while bar() only needs to read it once:

foo:
        mov     eax, DWORD PTR [rdi]
        add     DWORD PTR [rsi], 1
        add     eax, DWORD PTR [rdi]  # second read
        ret
bar:
        mov     eax, DWORD PTR [rdi]
        add     DWORD PTR [rsi], 1
        add     eax, eax              # no second read
        ret

See this live on GodBolt.

restrict is only a keyword in C (since C99); unfortunately, it has not been introduced into C++ so far (for the poor reason that more complicated to introduce it in C++). Many compilers do kinda-support it, however, as __restrict.

Bottom line: The compiler must support your "esoteric" use case when compiling f(), and will not have any problem with it.


See this post regarding use cases for restrict.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=368255&siteId=1
Recommended