Eingeschränkte Zeiger Fragen
-
25-09-2019 - |
Frage
Ich bin ein wenig verwirrt über die Regeln in Bezug auf eingeschränkte Zeiger. jemand da draußen kann mir vielleicht helfen.
-
Ist es legal, verschachtelt beschränkt Zeiger wie folgt zu definieren:
int* restrict a; int* restrict b; a = malloc(sizeof(int)); // b = a; <-- assignment here is illegal, needs to happen in child block // *b = rand(); while(1) { b = a; // Is this legal? Assuming 'b' is not modified outside the while() block *b = rand(); }
-
Ist es legal, einen eingeschränkten Zeigerwert abzuleiten, wie folgt:
int* restrict c; int* restrict d; c = malloc(sizeof(int*)*101); d = c; for(int i = 0; i < 100; i++) { *d = i; d++; } c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed? *c = rand();
Danke! Andrew
Lösung
Als Referenz ist hier die restrict
Qualifikationsspiel eher Definition gewunden (von C99 6.7.3.1 "formale Definition beschränken"):
sein Sei D eine Erklärung eines gewöhnlichen Bezeichner, stellt ein Mittel zur Bezeichnen eines Objekts P als beschränken qualifizierte Zeiger auf den Typ T.
Wenn D erscheint in einem Block und nicht Speicherklasse haben extern, lassen Sie B, um den Block zu bezeichnen. wenn D erscheint in der Liste der Parameter Erklärungen der Funktion Definition, lassen B bezeichnen die zugeordneten Block. Ansonsten lassen B bezeichnen den Hauptblock (oder den Block von was auch immer wird Funktion aufgerufen bei Programmstart in einem freistehenden Umwelt).
Im Folgenden eines Zeigers Ausdruck E wird gesagt werden, basierend auf Objekt P if (an einem gewissen Punkt Sequenz in der Ausführung von B vor dem Auswertung von E) P zum Punkt Modifizieren auf eine Kopie des Arrays Objekt in die darauf hingewiesen früher würde sich ändern der Wert von E. Man beachte, dass „basiert“ ist nur für Ausdrücke definiert mit Zeigertypen.
Während jeder Ausführung von B sei L sein jeder L-Wert, der & L hat auf Basis von P. Wenn L wird verwendet, um den Wert des für den Zugriff auf Objekt X dass es bezeichnet ist, und X auch (durch ein beliebiges Mittel) modifiziert, dann wird die gelten folgende Anforderungen: T wird nicht const qualifiziert sein. jede andere L-Wert verwendet, um den Wert von X zugreifen wird auch seine Adresse hat, basierend auf P. Jeder Zugriff dass X modifiziert wird in Betracht gezogen wird auch P zu verändern, Im Sinne dieses Subklausel. Wenn P wird, um den Wert eines Zeigers zugewiesen Ausdruck E die auf einem anderen basiert eingeschränktes Zeigerobjekt P2, mit dem Block B2 verbunden ist, dann entweder wird die Ausführung von B2 beginnen, bevor die Ausführung von B, oder Ausführung von B2 wird vor Ende zu die Zuordnung. Wenn diese Anforderungen nicht erfüllt sind, dann wird die Verhalten ist nicht definiert.
Hier ist eine Ausführung von B bedeutet, dass Teil der Ausführung der Programm, das auf dem entspräche Lebensdauer eines Objekts mit Skalartyp und eine automatische Lagerdauer im Zusammenhang mit B.
Meine Lektüre der obigen Mittel, dass in Ihrer ersten Frage, a
nicht b
zugeordnet werden kann, sogar in einem „Kind“ Block - das Ergebnis ist nicht definiert. Ein solche Zuordnung vorgenommen werden könnte, wenn b
in diesem ‚Unterblock‘ deklariert wurde, aber da b
im gleichen Umfang wie a
deklariert ist, kann die Zuordnung nicht vorgenommen werden.
Frage 2, die Zuordnungen zwischen c
und d
auch in undefiniertem Verhalten führen (in beiden Fällen).
Das entsprechende Bit aus dem Standard (für beiden Fragen) ist:
Wenn P den Wert von a zugeordnet ist, Zeiger Ausdruck E, die auf basiert ein anderes eingeschränktes Zeigerobjekt P2, mit dem Block B2 verbunden ist, dann entweder wird die Ausführung von B2 beginnen, bevor die Ausführung von B, oder Ausführung von B2 wird vor Ende zu die Zuordnung.
Da die eingeschränkten Zeiger mit dem gleichen Block zugeordnet sind, ist es nicht möglich, für den Block B2 vor der Ausführung B, oder B2 zu beginnen vor der Übertragung zu beenden (da B und B2 ist der gleiche Block).
Der Standard gibt ein Beispiel, das diese ziemlich klar macht (ich glaube - die Klarheit der vier kurzen Absätzen des restrict
Definition ist auf einer Stufe mit C ++ 's Namensauflösung Regeln):
Beispiel 4:
Die Regel Begrenzung Zuordnungen zwischen eingeschränkter Zeiger nicht unterscheiden zwischen einem Funktionsaufruf und ein äquivalenter verschachtelter Block. Mit einer Ausnahme nur „Outer-zu-innen“ Zuordnungen zwischen beschränkt Zeiger deklariert in verschachtelten Blöcke Verhalten definiert.
{ int * restrict p1; int * restrict q1; p1 = q1; // undefined behavior { int * restrict p2 = p1; // valid int * restrict q2 = q1; // valid p1 = q2; // undefined behavior p2 = q2; // undefined behavior } }
Andere Tipps
Der restrict
Qualifier ist ein Hinweis an die Compiler, dass, wenn der Speicher durch die restrict
qualifizierte Zeiger adressiert geändert wird, wird kein anderer Zeiger, die gleichen Speicher zugreifen. Der Compiler kann zu optimieren Code, auch wenn restrict
qualifizierten Zeiger auf eine Weise wählen, die sonst zu falschem Verhalten führen könnten. Es ist die Verantwortung des Programmierers, um sicherzustellen, dass beschränken qualifizierte Zeiger verwendet werden, wie sie gemeint waren verwendet werden. Andernfalls kann ein unerwartetes Verhalten. ( link )
Wie Sie aus der obigen Beschreibung sehen können, sowohl Ihre Zuweisungen illegal sind, dass möglicherweise von einigen Compiler erzeugt in ausführbaren Dateien arbeiten, aber in anderen brechen. Erwarten Sie nicht, den Compiler selbst Fehler oder Warnungen zu emittieren als restrict
nur eine Möglichkeit gibt, bestimmte Optimierung durchzuführen, die sie wählen können nicht ausführen, wie im Fall von volatile
.