Bei Verwendung eines beschränken Pointer in C, ist es OK, um eine Variable mit seinem ursprünglichen Identifier zu ändern?
-
30-09-2019 - |
Frage
Wenn Sie eine restrict
Pointer in C verwendet, ist es OK, um die Variable mit seinem ursprünglichen Identifier zu ändern? Zum Beispiel:
int foo = 0;
int * restrict fooPtr = &foo;
++(*fooPtr); // Part 1: foo is 1 (OK)
++foo; // Part 2: foo is 2 (Is this OK?)
int * fooPtr2 = &foo;
++(*fooPtr2); // Part 3: foo is 3 (BAD: You shouldn't access via a second pointer)
... änderte ich den Wert von foo durch foo nach dem restrict
fooPtr erstellt wurde.
Teil 1 sieht nicht gut aus für mich. Ich bin verwirrt über Teil 2 . Und von dem, was ich über restrict
verstehen, Teil 3 ist schlecht (Compiler ermöglicht es, aber sein Verhalten ist nicht definiert, und es ist für den Programmierer bis das nicht zu tun).
Lösung
Nein, Teil 2 ist nicht in Ordnung.
Der spezifische Teil der Norm ist 6.7.3.1/4. Dieser Abschnitt ist recht dicht und nimmt ein paar Wieder liest, aber P ist ein Zeiger beschränken, und X ist ein Objekt es für den Zugriff verwendet wird, und welche modifiziert wird. So in Ihrem Beispiel P ist fooPtr
und X foo
. Dann gilt:
Jeder anderer L-Wert verwendet, die für den Zugriff auf Wert von X wird auch seine Adresse basierend auf P.
„auf Basis von“ im vorhergehenden Absatz definiert ist, und zusammenfassen, die lvalue foo
tut nicht hat seine Adresse basierend auf dem Zeiger P. So beschränkt die Regel gebrochen wird, wenn Sie auf das Objekt zugreifen foo
durch seinen eigenen Namen.
Teil 3 ist nicht OK für genau den gleichen Grund, die L-Wert *fooPtr2
basiert nicht auf P entweder, sondern auch dem Zugriff auf X verwendet wird.
Ich sage „nicht in Ordnung“ - um genau zu sein, die Kombination aus 1 + 2 provoziert nicht definiertes Verhalten, wie auch die Kombination aus 1 + 3. Solange Sie das Objekt zugreifen nicht tatsächlich durch den Zeiger beschränken, keiner der Definition von „Kicks“ beschränken. Wenn Sie Sie wollte ein Teil entfernen konnte, behalten den ungenutzten beschränken Zeiger und dann 2 und 3 würde in Ordnung sein.
Andere Tipps
Ja "Teil 3" ist nicht definiertes Verhalten. Aus der C99-Spezifikation (6.7.3, Absatz 7):
Ein Objekt, das durch eine zugegriffen beschränken-qualifizierter ed Zeiger hat eine spezielle Verbindung mit diesem Zeiger. Dieser Verein, de fi niert in 6.7.3.1 unten erfordert, dass alle Zugriffe auf dass Objekt Verwendung, die direkt oder indirekt, dass der Wert von insbesondere Zeiger.
Ich würde sagen, # 2 schlecht ist. Zum Beispiel könnte der Compiler optimiert, indem sie den Wert an * fooPtr in ein Register geladen wird, und dann die zurück Registerwert wieder schreiben, um foo später - nach dem ++ foo, so dass die ++ foo verloren.
Unter der Annahme, dass alle Teile Ihrer Frage im selben Block auftreten, ist es nicht OK, um den Wert von foo
direkt zuzugreifen (Teil 2) noch den Zugriff auf sie über einen anderen Zeiger (Teil 3):
- 6.7.3.1 formale Definition beschränkt
Jeder anderer L-Wert verwendet, um den Wert von X zugreifen soll seine auch hat Adresse basierend auf P.
Die formale Definition von restrict
ziemlich schwierig ist, zu folgen (zumindest ist es für mich), aber die folgende weniger formale Beschreibung auch von den Standard-Summen es ziemlich gut (zumindest für diesen Fall):
Ein Objekt, das durch einen Filterung der qualifizierten Zeiger zugegriffen wird, hat eine besondere Assoziation mit diesem Zeiger. Dieser Verein, unten in 6.7.3.1 definiert ist, setzt voraus, dass alle Zugriffe auf das Objekt verwenden, die direkt oder indirekt den Wert des jeweiligen Zeigers.