Es stimmt zwar, dass das Verhalten genau definiert ist, aber es stimmt nicht , dass Compiler in dem von Ihnen gemeinten Sinne "für const optimieren" können.
Das heißt, ein Compiler darf nicht davon ausgehen, dass nur weil ein Parameter a ist const T* ptr
, der Speicher, auf den von ptr
zeigt, nicht durch einen anderen Zeiger geändert wird. Die Zeiger müssen nicht einmal gleich sein. Dies const
ist eine Verpflichtung, keine Garantie - eine Verpflichtung von Ihnen (= die Funktion), keine Änderungen über diesen Zeiger vorzunehmen.
Um diese Garantie tatsächlich zu haben, müssen Sie den Zeiger mit dem restrict
Schlüsselwort markieren . Wenn Sie also diese beiden Funktionen kompilieren:
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;
}
Die foo()
Funktion muss zweimal lesen x
, während sie bar()
nur einmal lesen muss:
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
Sehen Sie dies live weiter GodBolt.
restrict
ist nur ein Schlüsselwort in C (seit C99); Leider wurde es bisher nicht in C ++ eingeführt (aus dem schlechten Grund, dass die Einführung in C ++ komplizierter ist). Viele Compiler unterstützen es jedoch irgendwie als __restrict
.
Fazit: Der Compiler muss Ihren "esoterischen" Anwendungsfall beim Kompilieren f()
unterstützen und hat keine Probleme damit.
Siehe diesen Beitrag zu Anwendungsfällen für restrict
.
const
ist nicht „eine Verpflichtung von Ihnen (= der Funktion), keine Änderungen über diesen Zeiger vorzunehmen“. Der C-Standard ermöglicht es der Funktion,const
über einen Cast zu entfernen und das Objekt dann durch das Ergebnis zu modifizieren. Diesconst
ist im Wesentlichen nur eine Empfehlung und eine Annehmlichkeit für den Programmierer, um zu vermeiden, dass ein Objekt versehentlich geändert wird.memcpy
undstrcpy
wird mitrestrict
Argumenten deklariert , während diesmemmove
nicht der Fall ist - nur letzteres ermöglicht eine Überlappung zwischen den Speicherblöcken.Dies ist genau definiert (in C ++ nicht mehr sicher in C), mit und ohne
const
Qualifizierer.Das erste, wonach Sie suchen müssen, ist die strenge Aliasing-Regel 1 . If
src
unddst
zeigt auf dasselbe Objekt:char*
undchar const*
sind nicht kompatibel.char*
undchar const*
sind ähnlich.In Bezug auf das
const
Qualifikationsmerkmal könnten Sie argumentieren, dassdst == src
Sie nicht qualifiziert werden sollten , wenn Ihre Funktion effektiv ändert, auf welchesrc
Punkte verwiesen wird . So funktioniert das nicht. Zwei Fälle müssen berücksichtigt werden:src
const
const
const
wie in definiert ist ,char const data[42];
führt das Ändern (direkt oder indirekt) zu undefiniertem Verhalten.const
Objekt wie in definiert istchar const* pdata = data;
, kann das zugrunde liegende Objekt geändert werden, sofern es nicht alsconst
2 definiert wurde (siehe 1.). Folgendes ist also genau definiert:1) Was ist die strenge Aliasing-Regel?
2) Ist
const_cast
sicher?quelle
char*
undchar const*
sind nicht kompatibel._Generic((char *) 0, const char *: 1, default: 0))
ergibt null.const
Objekt definiert ist“ ist falsch. Sie meinen, wenn eine Referenz oder ein Zeiger auf einenconst
qualifizierten Typ definiert ist, bedeutet dies nicht, dass das Objekt, auf das es zeigen soll, möglicherweise nicht geändert wird (auf verschiedene Weise). (Wenn der Zeiger auf einconst
Objekt zeigt, bedeutet dies, dass das Objekt tatsächlichconst
per Definition ist, sodass das Verhalten beim Versuch, es zu ändern, nicht definiert ist.)language-lawyer
. Genauigkeit ist ein Wert, den ich schätze, aber ich bin mir auch bewusst, dass er komplexer ist. Hier habe ich mich für Einfachheit und leicht verständliche Sätze entschieden, weil ich glaube, dass dies das ist, was OP wollte. Wenn Sie etwas anderes denken, antworten Sie bitte, ich bin einer der Ersten, die es positiv bewerten. Trotzdem danke für deinen Kommentar.Dies ist in C genau definiert. Strikte Aliasing-Regeln gelten weder für den
char
Typ noch für zwei Zeiger desselben Typs.Ich bin mir nicht sicher, was Sie unter "Optimieren für
const
" verstehen . Mein Compiler (GCC 8.3.0 x86-64) generiert in beiden Fällen genau den gleichen Code. Wenn Sierestrict
den Zeigern den Bezeichner hinzufügen , ist der generierte Code etwas besser, aber das funktioniert in Ihrem Fall nicht, da die Zeiger gleich sind.(C11 §6.5 7)
In diesem Fall (ohne
restrict
) erhalten Sie immer121
als Ergebnis.quelle