12.13 Der »restrict«-Zeiger
Mit dem C99-Standard wurde der Typqualifizierer restrict neu eingeführt. Mit diesem Schlüsselwort können Sie Zeiger qualifizieren, sogenannte restrict-Zeiger. Der restrict-Zeiger hat eine enge Beziehung zu dem Speicherobjekt, auf das er verweist. Mit dem Qualifizierer geben Sie quasi vor, dass während der Lebensdauer des Zeigers das Speicherobjekt, auf das dieser verweist, nicht verändert werden kann und der Zugriff nur über diesen restrict-Zeiger erfolgen darf. Einfachstes Beispiel:
int * restrict iRptr = malloc (sizeof (int) );
Damit geben Sie praktisch vor, dass Sie den von malloc() zurückgegebenen reservierten Speicher nur mit dem Zeiger iRptr verwenden. Wohlgemerkt: Mit dem Qualifizierer restrict geben Sie nur dem Compiler das Versprechen, dass Sie auf das Speicherobjekt ausschließlich mit diesem Zeiger zurückgreifen. Jede Manipulation außerhalb des restrict-Zeigers, und sei es nur lesend, ist unzulässig.
Zu überprüfen, ob der restrict-Zeiger richtig verwendet wird, Sie also nur über diesen Zeiger auf ein Speicherobjekt zugreifen, ist Ihre Aufgabe. Der Compiler kann nicht überprüfen, ob Sie Ihr Versprechen eingehalten haben. Fall Sie die Regeln nicht einhalten, gibt es zwar keine Fehlermeldung des Compilers und häufig auch keine Probleme bei der Ausführung des Programms, aber dennoch ist das Verhalten laut Standard undefiniert. Abgesehen davon: Mit oder ohne den restrict-Zeiger bleibt die Ausführung des Programms dieselbe.
Der Vorteil des restrict-Zeigers ist es, dass Sie es dem Compiler ermöglichen, Optimierungen des Maschinencodes durchzuführen, die sonst bei Zeigern zu Problemen führen können. Allerdings muss der Compiler auch diesem Hinweis nicht nachkommen und kann den Qualifizierer restrict auch ignorieren.
Der restrict-Zeiger kann auch sehr gut bei Funktionen verwendet werden, um anzuzeigen, dass sich zwei Zeiger in der Parameterliste nicht überlappen dürfen, sprich, dasselbe Speicherobjekt verwenden. Beispielsweise ist bei
int flaeche( int * w, int * b ) { /* ... * / }
nicht klar angegeben, ob sich die beiden Speicherobjekte, auf die die Zeiger w und h verweisen, überlappen dürfen oder nicht. Mit dem neuen Qualifizierer restrict ist dies jetzt sofort erkennbar:
int flaeche( int * restrict w, int * restrict b ) { /* ... * / }
Wird trotzdem versucht, die Funktion mit sich überlappenden Speicherobjekte aufzurufen, ist das weitere Verhalten undefiniert. Ein ungültiger Aufruf kann beispielsweise wie folgt aussehen:
int val, x=20, y=10; // Unzulässig, wegen den restrict-Zeigern, // zwei gleiche Speicherobjekte werden verwendet, // die sich somit überlappen val = flaeche( &x, &x ); // OK, zwei verschiedene Speicherobjekte val = flaeche( &x, &y );
Vom restrict-Zeiger wird mittlerweile auch rege in der Standard-Bibliothek Gebrauch gemacht. Beispielsweise sieht die Syntax der Funktion strncpy() wie folgt aus:
#include <string.h> char *strncpy( char * restrict s1, const char * restrict s2, size_t n );
Die Funktion kopiert n Bytes vom Quellarray s2 in das Zielarray s1. Dadurch, dass die beiden Zeiger als restrict deklariert sind, müssen Sie beim Aufruf der Funktion beachten, dass die Zeiger nicht auf dieselben Speicherobjekte verweisen, sprich. sich nicht überlappen. Betrachten Sie dazu folgendes Beispiel:
char arr1[20]; char arr2[] = { "Hallo Welt" }; // Ok, 10 Zeichen von arr2 nach arr1 kopieren strncpy( arr1, arr2, 10 ); arr1[10] = '\0' // Unzulässig, Speicherbereiche überlappen sich, // das gibt nur Datensalat. strncpy( arr1, arr1, 5 );
Ein weiteres klassisches Beispiel von Funktionen der Standardbibliothek sind die Funktionen memcyp() und memmove() in der Headerdatei <string.h>. Die Syntax der Funktionen lautet:
#include <string.h> void *memcpy( void * restrict s1, const void * restrict s2, size_t n ); void *memmove( void *s1, const void *s2, size_t n);
Bei diesen beiden Funktionen kann man sehr schön sehen, dass sich bei memcpy() der Quell- und der Zielbereich nicht überlappen dürfen, weil sonst die restrict-Regel verletzt würde. Bei der anderen Standardfunktion memmove() hingegen dürfen sich der Quell- und der Zielbereich überlappen.
Hinweis |
Da sich der C99-Standard noch nicht auf allen Compilern komplett durchgesetzt hat, wurde bei den Beispielen in diesem Buch auf restrict-Zeiger verzichtet. Die Syntaxbezeichnungen der Standardfunktionen hingegen wurden bereits im C99-Standard verfasst. |
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.