Während ich cpreference durchsuchte, sah ich ein seltsames Typ-Array in Funktionsparametern wie diesem:
void f(double x[volatile], const double y[volatile]);
Also, was ist der Zweck der volatile
Schlüsselwort, das in einem Array-Index erscheint? Was tut es?
Das volatile
Schlüsselwort wird verwendet, um einen Array-Typ eines Funktionsparameters zu deklarieren.
Hier, double x[volatile]
ist äquivalent zu double * volatile x
.
Das cpReferenz sagt:
In einer Funktionsdeklaration das Stichwort volatile
kann innerhalb der eckigen Klammern erscheinen, die verwendet werden, um einen Array-Typ eines Funktionsparameters zu deklarieren. Es qualifiziert den Zeigertyp, in den der Array-Typ transformiert wird. Die folgenden beiden Deklarationen deklarieren dieselbe Funktion:
void f(double x[volatile], const double y[volatile]);
void f(double * volatile x, const double * volatile y);
Diese Syntax ist nur in der C-Sprache in Funktionsparametern gültig.
Im Allgemeinen erlaubt diese C-Funktion (und nur C!) die Angabe eines beliebigen Typqualifizierers innerhalb der Array-Klammern; Das genaue Standardangebot lautet:
Eine Deklaration eines Parameters als ”array of type” soll auf ”qualified pointer to type” angepasst werden, wobei die Typqualifizierer (falls vorhanden) diejenigen sind, die in der angegeben sind [
and ]
der Array-Typ-Ableitung. Wenn das Schlüsselwort static
erscheint auch innerhalb der [
and ]
der Array-Typ-Ableitung, dann muss für jeden Aufruf der Funktion der Wert des entsprechenden tatsächlichen Arguments den Zugriff auf das erste Element eines Arrays mit mindestens so vielen Elementen ermöglichen, wie durch den Größenausdruck angegeben.
(C99, §6.7.5.3, ¶7, Hervorhebung hinzugefügt)
Dies bedeutet, dass dies nicht nur darauf beschränkt ist volatile
aber const
und restrict
sind ebenfalls erlaubt (vgl Geben Sie Qualifizierer ein§6.7.3 Abs. 1).
Der Sinn dieses Hacks besteht im Wesentlichen darin, dass Sie einen Typqualifizierer hinzufügen können zum Parameter (nicht zum Element des Arrays) und behalten dennoch die Array-Syntax für die Deklaration bei; Ohne diese Syntax sind Sie gezwungen, darauf zurückzugreifen, es als Zeiger zu schreiben (worauf es sowieso hinausläuft mit Ausnahme der static
Fallfür die AFAIK keine äquivalente Zeigersyntax hat).
Ich vermute, dass die Idee hauptsächlich darin besteht, die Syntax für mehrdimensionale Arrays etwas weniger umständlich zu machen. Zitat aus §6.7.5.3 Abs. 21:
void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
sind alle gleichwertig, aber 2 und 3 können etwas besser vermitteln, dass dies nicht nur ein Zeiger, sondern ein Array ist, und dennoch einen Platz zum Platzieren der restrict
Qualifikation.
Außerdem scheint es, wie oben gesagt, keine Möglichkeit zu geben, so etwas zu haben
void f(double a[restrict static 3][5]);
(was “auch angibt, dass das entsprechende Argument a
in jedem Aufruf an f
muss ein Nicht-Null-Zeiger auf das erste von mindestens drei Arrays von 5 Doubles sein”, ebenda) mit der “normalen” Zeigersyntax.
Trotzdem würde ich mich von dieser Syntax fernhalten; Es ist extrem obskur und wird selten verwendet (ich glaube nicht, dass ich jemals einen Typqualifizierer zu einem Array hinzufügen musste Parameter – wieder der Parameter selbst, nicht der Elementtyp; restrict
ist der einzige Anwendungsfall, der sinnvoll sein kann) – und nicht nach C++ portierbar (was im Allgemeinen relevant ist, wenn Sie eine Bibliothek schreiben).
Das Ziel dieser Syntax ist einfach, den Code unlesbar zu machen 😉 Ich werde das zu dem “niemals tun” in unseren Codierungsrichtlinien hinzufügen 🙂
– Klaus
19. November 2017 um 13:55 Uhr