C99 fügte unter anderem das Schlüsselwort „restrict“ hinzu, um einem Programmierer die Möglichkeit zu geben, anzugeben, dass ein Zeiger der einzige Zeiger auf ein bestimmtes Objekt in einem Bereich ist, und dem Compiler folglich einen „Hinweis“ zu geben ” dass es zusätzliche Optimierungen durchführen kann, wenn über diesen Zeiger auf das Objekt zugegriffen wird.
Um das Problem zu veranschaulichen, das „Restrict“ lösen sollte, betrachten Sie eine Funktion wie:
void update_ptrs( int *p, int *q, int const *v ) { *p = *v; *q = *v; }
für den der Compiler x86-64-Code wie folgt generiert:
mov eax, [rdx] ; tmp = *v // 1 add [rdi], eax ; *p = tmp mov eax, [rdx] ; tmp = *v // 3 add [rsi], eax ; *q = tmp
Sie fragen sich vielleicht, warum Zeile 3 generiert wird, da sie mit Zeile 1 überflüssig zu sein scheint. Das Problem ist, dass der Compiler nicht wissen kann, dass Sie so etwas nicht getan haben:
int x = 1, v = 2; update_ptrs( &v, &x, &v ); // x = 5, v = 4
In update_ptrs() würden p und v alias das gleiche int sein, daher muss der Compiler auf Nummer sicher gehen und davon ausgehen, dass sich der Wert von *v zwischen den Lesevorgängen ändern kann. daher die zusätzliche mov-Anweisung.
Im Allgemeinen verwirren Zeiger in C die Optimierung, da der Compiler nicht wissen kann, ob sich zwei Zeiger gegenseitig aliasen. Bei leistungskritischem Code könnte das Eliminieren von Speicherlesevorgängen ein großer Gewinn sein wenn der Compiler dies sicher tun könnte.
Die Lösungeinzige Zeiger auf ein Objekt im Gültigkeitsbereich des Zeigers ist, d. h. kein anderer Zeiger im gleichen Bereich Aliase Es.
Um „restrict“ zu verwenden, fügen Sie eszwischen dem * und dem Namen des Zeigers in einer Deklaration ein. Eine zur Verwendung von „restrict“ umgeschriebene update_ptrs() wäre:
void update_ptrs_v2( int *restrict p, int *restrict q, int const *restrict v ) { *p = *v; *q = *v; }(Lesen von rechts nach links, z. B. ist v ein eingeschränkter Zeiger auf eine Konstante int; oder verwenden Sie cdecl.)
Durch das Hinzufügen von „restrict“ kann der Compiler jetzt Code generieren wie:
void update_ptrs_v2( int *restrict p, int *restrict q, int const *restrict v ) { *p = *v; *q = *v; }Jetzt konnte der Compiler die vorherige Zeile 3 der zusätzlichen mov-Anweisung eliminieren.
Das vielleicht bekannteste Beispiel für die Verwendung von Restrict ist die Standardbibliotheksfunktion memcpy(). Dies ist der schnellste Weg, einen Teil des Speichers zu kopieren,
wenn sich die Quell- und Zieladressen nicht überschneiden. Die etwas langsamere memmove()-Funktion existiert für den Einsatz, wenn sich die Adressen do überschneiden.
Fallstrickeeinigen Fällen kann der Compiler Sie warnen, aber nicht in allen Fällen. Verlassen Sie sich also nicht darauf, dass der Compiler Missbrauch erkennt. Beachten Sie, dass die Einschränkung für einen bestimmten Bereich gilt. Das Zuweisen eines eingeschränkten Zeigers zu einem anderen im selben Bereich
führt zu undefiniertem Verhalten:
void f( int *restrict d, int *restrict s ) {
int *restrict p = s; // undefiniertes Verhalten
void f( int *restrict d, int *restrict s ) { int *restrict p = s; // undefined behavior
void f( int *restrict d, int *restrict s ) {
int *p = s; // OK
void f( int *restrict d, int *restrict s ) { int *p = s; // OKEs ist auch in Ordnung, einen eingeschränkten Zeiger in einem inneren Bereich einem anderen in einem äußeren Bereich zuzuweisen (aber nicht umgekehrt):
void f( int *restrict d, int *restrict s ) {
{ // innerer Bereich
int *restrict p = s; // OK
// ...
s = p; // undefiniertes Verhalten
}
}
void f( int *restrict d, int *restrict s ) { int *p = s; // OKZuerst sollten Sie auf jeden Fall ein Profil Ihres Codes erstellen (und sich vielleicht sogar den generierten Assembler-Code ansehen), um zu sehen, ob die Verwendung von „Restrict“ tatsächlich zu einer
sehr schwierig. Zweitens ist es sicherer, wenn die Verwendung von „restrict“ auf die Implementierung einer Funktion beschränkt ist, bei der der Speicher, auf den über eingeschränkte Zeiger zugegriffen wird, von Sie
zugewiesen wurde. Zum Beispiel gegeben:
void sicherer( unsigned n ) {
n = n % 2 != 0; // durch Aufrunden ausgeglichen werden
int *const array = malloc( n * sizeof(unsigned) );
unsigned *restrict half_1st = array;
unsigned *restrict half_2nd = array n/2;
// ...
free( array );
}
void f( int *restrict d, int *restrict s ) { int *p = s; // OKDrittens ist die Verwendung von „restrict“ in den Parametern einer Funktion möglicherweise
weniger
sicher. Vergleichen Sie beispielsweise „safer()“ mit „update_ptrs_v2()“, wobei derAufrufer die Zeiger steuert. Soweit Sie wissen, hat der Anrufer es falsch verstanden und Zeiger auf diesen Alias übergeben. Verschiedenes Nur
Zeiger auf Objekte (oder void) können mit „restrict:“ qualifiziert werden:restrict int x; // Fehler: Objekt kann nicht eingeschränkt werden
int beschränken *p; // Fehler: Zeiger auf Einschränkungsobjekt
int (*restrict f)(); // Fehler: Zeiger auf Funktion
Sie können „restrict“ für Strukturmitglieder verwenden, zum Beispiel:
restrict int x; // error: can't restrict object int restrict *p; // error: pointer to restrict object int (*restrict f)(); // error: pointer-to-function
besagt, dass Daten der einzige Zeiger auf diese Daten sind und dass links und rechts niemals auf denselben Knoten zeigen. Die Verwendung von „restrict“ für Strukturmitglieder ist jedoch sehr ungewöhnlich.
struct node { void *restrict data; struct node *restrict left; struct node *restrict right; };Einschränkung. Warum nicht? Es gibt eine lange Antwort, aber die TL;DR-Version lautet:
Es kann eine Quelle schwer zu findender Fehler sein, die das C-Komitee nicht aus C importieren wollte. Cs verstärkte Verwendung von Zeigern, z. B. this, macht die sichere Verwendung von „restrict“ noch schwieriger.
Mit Bedacht verwenden.
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3