Strenge Aliasing-Regel und ‘char *’-Zeiger

Lesezeit: 8 Minuten

Strenge Aliasing Regel und char Zeiger
Benutzer3489275

Die akzeptierte Antwort auf Was ist die strikte Aliasing-Regel? Erwähnungen, die Sie verwenden können char * einen anderen Typ zu aliasieren, aber nicht umgekehrt.

Es ergibt für mich keinen Sinn – wenn wir zwei Zeiger haben, einen vom Typ char * und eine andere Art struct something * Wie ist es möglich, dass der erste Alias ​​für den zweiten ist, aber der zweite nicht für den ersten, wenn er auf denselben Ort zeigt?

  • Sie können ein lesen T über ein char *aber Sie können keine beliebige lesen char Puffer über a T *.

    – Oliver Charlesworth

    24. Mai 2014 um 18:09 Uhr


  • Es ist eine Regel, sonst nichts … Grundsätzlich kann der Compiler mehr optimieren (wie bei restrict) … Aber auch Compiler-Jungs sind IMHO faul …

    – Macmade

    24. Mai 2014 um 18:13 Uhr

  • Dies ist einer der Orte, an denen C/C++ nicht auf die gleiche Weise funktionieren

    – Grady-Spieler

    24. Mai 2014 um 18:14 Uhr

  • @ user3489275: Warten Sie, vielleicht war meine Referenz nicht klar – das Umwandeln des Zeigers ist in Ordnung, aber nicht das Schreiben in den Speicher eines Objekts über einen Zeichenzeiger. Dh wenn Sie in den Speicher schreiben, machen Sie das ursprüngliche Objekt ungültig. Das Lesen der Bytes der zugrunde liegenden Darstellung eines Objekts durch einen char-Zeiger ist vollkommen in Ordnung (und tatsächlich funktioniert jede E/A so).

    – Kerrek SB

    24. Mai 2014 um 18:26 Uhr

  • @KerrekSB: Das ist es nicht UB, um den Speicher eines Objekts mit einem nicht-trivialen Destruktor wiederzuverwenden (und somit die Lebensdauer zu beenden). So seltsam es auch klingen mag, der Standard sagt ausdrücklich, dass dies nur dann undefiniert ist, wenn das Programm von Seiteneffekten des Destruktors abhängt. Außerdem glaube ich nicht, dass das Schreiben durch die char* endet die Lebensdauer des Objekts. Verwenden Sie die Platzierung neu, sicher, schreiben Sie einfach durch einen Zeiger … nicht so sicher.

    – David Rodríguez – Dribeas

    24. Mai 2014 um 20:00 Uhr


wenn wir zwei Zeiger haben, einen vom Typ char * und eine andere Art struct something * Wie ist es möglich, dass der erste Alias ​​für den zweiten ist, aber der zweite nicht für den ersten, wenn er auf denselben Ort zeigt?

Das tut es, aber darum geht es nicht.

Der Punkt ist, dass, wenn Sie eine oder mehrere haben struct somethings dann können Sie a verwenden char* um ihre konstituierenden Bytes zu lesen, aber wenn Sie ein oder mehrere haben chars dann dürfen Sie a nicht verwenden struct something* sie zu lesen.

  • Der Grund, warum ein char* einen anderen Typ aliasieren darf, liegt einfach darin, dass es eine sehr einfache Möglichkeit zum Serialisieren einer Struktur bietet und ein häufig verwendetes Muster ist.

    – doron

    30. Juni 2015 um 11:57 Uhr

  • und jetzt weiß es auch der OP.

    – doron

    30. Juni 2015 um 15:13 Uhr

  • Definiere “Du hast ein oder mehrere Zeichen”

    – Neugieriger

    14. August 2015 um 10:25 Uhr

  • @curiousguy: Was ist unklar? char buf[sizeof(something)] = {}; something* ptr = reinterpret_cast<something*>(&buf[0]); // invalid

    – Leichtigkeitsrennen im Orbit

    14. August 2015 um 10:32 Uhr


  • Das ganze Konzept des “Habens”. Ein Zeichen ist ein Byte. Jede Objektdarstellung ist ein Bündel von Bytes oder Zeichen. Sie haben immer ein oder mehrere Zeichen.

    – Neugieriger

    14. August 2015 um 10:35 Uhr

Strenge Aliasing Regel und char Zeiger
MikeMB

Der Wortlaut in der referenzierten Antwort ist leicht fehlerhaft, also lassen Sie uns das zuerst ausbügeln: Eins Objekt aliasiert niemals einen anderen Objektaber zwei Zeiger kann dasselbe Objekt “aliasieren” (was bedeutet, dass die Zeiger auf denselben Speicherort zeigen – wie MM darauf hingewiesen hat, ist dies immer noch nicht 100% korrekt, aber Sie verstehen die Idee). Außerdem spricht der Standard selbst (meines Wissens nach) überhaupt nicht von striktem Aliasing, sondern gibt nur Regeln vor, durch welche Arten von Ausdrücken auf ein Objekt zugegriffen werden darf oder nicht. Compiler-Flags wie ‘-fno-strict-aliasing’ teilen dem Compiler mit, ob er davon ausgehen kann, dass der Programmierer diese Regeln befolgt hat (so dass er Optimierungen basierend auf dieser Annahme durchführen kann) oder nicht.

Nun zu Ihrer Frage: Beliebig Objekt erreichbar über a Zeiger zu charaber ein char Objekt (insbesondere auf ein char-Array) kann nicht über die meisten anderen Zeigertypen zugegriffen werden. Davon ausgehend kann/muss der Compiler folgende Annahmen treffen:

  1. Wenn der Typ des tatsächlichen Objekts selbst nicht bekannt ist, a char* und T* könnten immer auf dasselbe Objekt zeigen (aliasieren) -> symmetrische Beziehung.
  2. Wenn T1und T2 sind nicht “verwandt” und nicht chardann T1* und T2* darf nie auf dasselbe Objekt zeigen -> symmetrische Beziehung
  3. EIN char* kann auf a hinweisen char Oder ein T Objekt
  4. EIN T* darf NICHT auf ein hinweisen char Objekt -> einsymmetrische Beziehung

Ich glaube, der Hauptgrund für die asymmetrisch Regeln für den Zugriff Objekt durch Zeiger ist, dass a char Das Array erfüllt möglicherweise nicht die Ausrichtungsanforderungen von zB an int.

Also auch ohne Compiler-Optimierungen nach der strikten Aliasing-Regel, zB Schreiben an int an die Stelle eines 4-Byte char Array an den Adressen 0x1,0x2,0x3,0x4 führt im besten Fall zu schlechter Leistung und im schlimmsten Fall zum Zugriff auf einen anderen Speicherort, da die CPU-Befehle beim Schreiben eines 4- Byte-Wert (hier könnte dies also zu einem Schreiben auf 0x0,0x1,0x2 und 0x3 führen).

Bitte beachten Sie auch, dass die Bedeutung von “related” von Sprache zu Sprache (zwischen C und C++) unterschiedlich ist, aber das ist für Ihre Frage nicht relevant.

  • Die Ausrichtung ist KEINE Begründung für die strenge Aliasing-Regel, geschweige denn die wichtigste. Es ist ein orthogonales Problem. Der Grund für die Aliasing-Regel besteht darin, Optimierungen zu ermöglichen. (manchmal auch TBAA genannt – typbasierte Aliasing-Analyse). Außerdem geht es bei der Regel auch nicht darum, dass Zeiger sich gegenseitig Aliasnamen geben. Es geht um einen Lvalue, der ein Objekt aliasiert.

    – MM

    30. Juni 2015 um 11:54 Uhr

  • @MM: Ich habe nicht gesagt, dass dies der Hauptgrund für die strenge Aliasing-Regel selbst ist, aber warum zB a char* kann auf ein hinweisen int während ein int* darf nicht auf ein char-Array zeigen. Ich habe meinen Beitrag korrigiert, sodass es nicht mehr um zwei Zeiger geht, die sich gegenseitig aliasieren. Vielleicht kannst du nochmal nachschauen?

    – MikeMB

    30. Juni 2015 um 12:46 Uhr


  • Nehmen Sie auch den Absatz heraus, der mit „Die Hauptbegründung“ beginnt; Ausrichtung ist keine Begründung für Aliasing-Regeln

    – MM

    30. Juni 2015 um 12:57 Uhr


  • @MM: Entschuldigung, ich bin in diesem Teil zufällig anderer Meinung als Sie und der folgende Absatz erklärt, warum ich denke, dass es eine gültige Begründung ist. Noch einmal, ich sage nicht, dass es eine Begründung für die strenge Aliasing-Regel selbst ist, aber für diesen spezifischen Teil davon.

    – MikeMB

    30. Juni 2015 um 13:15 Uhr


  • Die Aliasing-Regeln gelten sogar für ausgerichteten Speicher.

    – Neugieriger

    14. August 2015 um 10:42 Uhr

wenn wir zwei Zeiger haben, einen vom Typ char * und eine andere Art struct something * Wie ist es möglich, dass der erste Alias ​​für den zweiten ist, aber der zweite nicht für den ersten, wenn er auf denselben Ort zeigt?

Zeiger aliasieren einander nicht; das ist schlampiger Sprachgebrauch. Aliasing ist, wenn ein Wert wird verwendet, um auf eine zuzugreifen Objekt anderer Art. (Das Dereferenzieren eines Zeigers ergibt einen lvalue).

In Ihrem Beispiel ist der Typ des Objekts wichtig, für das ein Alias ​​verwendet wird. Nehmen wir für ein konkretes Beispiel an, dass das Objekt a ist double. Zugriff auf die double durch Dereferenzieren a char * Das Zeigen auf das Doppel ist in Ordnung, da die strenge Aliasing-Regel dies zulässt. Der Zugriff auf a double durch Dereferenzieren a struct something * ist nicht zulässig (es sei denn, die Struktur beginnt wohl mit double!).

Wenn der Compiler eine Funktion betrachtet, die dauert char * und struct something *, und es verfügt nicht über die Informationen über das Objekt, auf das gezeigt wird (dies ist eigentlich unwahrscheinlich, da Aliasing-Durchgänge in einer Optimierungsphase des gesamten Programms durchgeführt werden); dann müsste es die Möglichkeit berücksichtigen, dass das Objekt tatsächlich a sein könnte struct something *sodass innerhalb dieser Funktion keine Optimierung durchgeführt werden konnte.

  • Das Dereferenzieren einer Struktur hat keine Auswirkung, es liest keinen Speicher.

    – Neugieriger

    18. August 2015 um 16:48 Uhr

  • @curiousguy Der lvalue, der durch Dereferenzieren eines Zeigers auf struct erzeugt wird, kann zum Lesen oder Schreiben von Speicher verwendet werden. Zum Beispiel struct something *x = whatever; *x = bla;

    – MM

    19. August 2015 um 0:39 Uhr


  • Ich würde Aliasing so beschreiben, dass es auftritt, wenn der Speicher über zwei unabhängige Mittel adressiert oder aufgerufen wird, jeweils innerhalb der aktiven Lebensdauer des anderen. Wenn man Aliasing auf diese Weise definieren und angeben würde, dass 6.5p7 nur in Fällen gilt, in denen diese Form von Aliasing tatsächlich enthalten wäre, würde dies die Notwendigkeit des Effektivtyp-Unsinns sowie der Ausnahme des Zeichentyps beseitigen und gleichzeitig zulassen mehr Optimierungen als unter C99 erlaubt sind, während die Verwendung von mehr Code ermöglicht wird, der sonst erforderlich wäre -fno-strict-aliasing.

    – Superkatze

    12. Juli 2018 um 20:48 Uhr

  • Wenn Code sagen würde short *p =(short*)someObject; *p+=1; und niemals verwenden p Auch dies sollte nicht als Aliasing angesehen werden, da die aktive Lebensdauer von p würde sich nur bis zu seiner letzten Verwendung erstrecken, und someObject niemals auf andere Weise als darauf zugegriffen werden würde p innerhalb dieser Zeit. Wenn jedoch Code einige Zugriffe auf ausführen würde someObject(without using P) before accessing those same parts with P, the accesses to someObject` würde den lvalue aliasieren *p das war aktiv mit diesen Teilen verbunden. Zu erkennen, was Aliasing ist und was nicht, würde den Standard enorm vereinfachen.

    – Superkatze

    12. Juli 2018 um 20:53 Uhr

924480cookie-checkStrenge Aliasing-Regel und ‘char *’-Zeiger

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy