C++Guns – RoboBlog

15.08.2018

C++ Guns: why C++ ist better than C. Or: keyword restrict is useless

Filed under: Allgemein — Tags: — Thomas @ 19:08

Das restricted keyword in C

restrict keyword...is basically a promise to the compiler that for the scope of the pointer, the target of the pointer will only be accessed through that pointer (and pointers copied from it).

In C++ geben wir keine Versprechen. Grundsätzlich nicht.
Das Beispiel von cppreference.com verdeutlich das Optimierungspotential ziemlich anschaulich. Gegeben ist folgende Funktion:

int foo(int &a, int &b) {
    a = 5;
    b = 6;
    return a + b;
}
foo(int&, int&):
        movl    $5, (%rdi)     # store 5 in a
        movl    $6, (%rsi)     # store 6 in b
        movl    (%rdi), %eax   # read back from a in case previous store modified it
        addl    $6, %eax       # add 6 to the value read from a
        ret

Welche Optimierungsmöglichkeiten gibt es hier? Natürlich, der Rückgabewert ist 11 (5+6), solange die Referenzen von a und b auf unterschiedliche Variablen zeigen. Sonst ist der Rückgabewert 12 (6+6). Mit dem restrict keyword kann man lügen und behaupten, dass die Referenzen von a und b nicht auf die selbe Variablen zeigen. Aber so etwas haben wir in C++ nicht nötigt; der Compiler weiss es besser als wir.
Je nachdem in welchen Kontext die Funktion foo aufgerufen wird, kann optimiert werden, oder auch nicht. Beispielsweise ist in Funktion func zur Compilezeit sichergestellt, dass die Referenzen auf unterschiedliche Variablen zeigen. Entsprechend wird der Rückgabewert von 11 voraus berechnet und im Code abgelegt.

auto func(std::vector<int>& arr, size_t i) {
    return foo(arr[i], arr[i+1]);
}
func(std::vector<int, std::allocator<int> >&, unsigned long):
        movq    (%rdi), %rax
        addq    $1, %rsi             # temp increment i
        movl    $5, -4(%rax,%rsi,4)  # store 5 in a
        movl    $6, (%rax,%rsi,4)    # store 6 in b
        movl    $11, %eax            # the result is 11, a compile-time constant
        ret

Zeigen die Referenzen hingegen auf die selbe Variable, wie in der Funktion func2, erkennt auch dies der Compiler und berechnet einen anderen Rückgabewert: 12. Auch in diesem Fall muss die Addition zur Laufzeit nicht ausgeführt werden.

auto func2(std::vector<int>& arr, size_t i) {
    return foo(arr[i], arr[i]);
}
func2(std::vector<int, std::allocator<int> >&, unsigned long):
        movq    (%rdi), %rax
        movl    $6, (%rax,%rsi,4)  # store 6 in a and b.
        movl    $12, %eax          # the result is 12, a compile-time constant
        ret

Fazit: Hinweise an den Compiler mit dem restrict keyword in C sind in C++ absolut überflüssig und führen nur zu undefinierten Verhalten des Programms und damit zu schwer findbaren Bugs. Da die Debugzeit 1/3 bis gerne 2/3 der gesamten Entwicklungszeit ausmachen (in der Praxis, nicht in der Theorie), ist der Einsatz von C statt C++ unwirtschaftlich.

[1] https://en.cppreference.com/w/c/language/restrict
[2] https://stackoverflow.com/questions/776283/what-does-the-restrict-keyword-mean-in-c

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress