Korrektes Verhalten von trivialen Anweisungen, die Ausdrücke mit flüchtigen Variablen enthalten?

8

Beachten Sie die folgenden Anweisungen

%Vor%

Nun habe ich versucht, einen Punkt im Standard zu finden, der mir sagt, wie sich ein Compiler verhalten soll, wenn er auf diese Anweisungen stößt. Alles, was ich finden konnte, ist, dass A (und möglicherweise C) mir einen Wert gibt, und auch B:

"§ 5.1.1.8 Primäre Ausdrücke - Allgemein" sagt

  

Ein Bezeichner ist ein ID-Ausdruck, sofern er entsprechend angegeben wurde (Abschnitt 7). [..]
  [..] Das Ergebnis ist die Entität, die durch den Bezeichner gekennzeichnet ist. Das Ergebnis ist ein   Lvalue, wenn die Entität eine Funktion, eine Variable oder ein Datenmember und a ist   prvalue sonst.
  [..]

"§ 5.3.1 Unäre Operatoren" sagt

  

Der unäre * Operator führt eine Indirektion durch: Der Ausdruck, auf den er angewendet wird, soll ein Zeiger auf einen Objekttyp oder ein Zeiger auf einen Funktionstyp sein, und das Ergebnis ist ein L-Wert, der auf das Objekt oder die Funktion verweist, auf die der Ausdruck zeigt .

clang und gcc

Ich probierte das mit clang ++ 3.2-11 und g ++ 4.7.3, und das erste produzierte drei liest im C ++ 11-Modus und Null liest im C ++ 03-Modus (gibt drei Warnungen aus), während g ++ nur die ersten beiden erzeugte , warnt mich ausdrücklich, dass der dritte nicht generiert werden würde.

Frage

Es ist klar, welcher Werttyp aus dem Ausdruck herauskommt, aus der zitierten Zeile im Standard, aber:
welche der Aussagen (A, B, C) sollte einen Lesevorgang vom flüchtigen erzeugen Entität nach dem C ++ - Standard?

    
bitmask 27.11.2013, 12:44
quelle

2 Antworten

5

Die G ++ - Warnung über die "implizite Dereferenzierung" stammt vom Code in gcc/cp/cvt.c , der den Wert absichtlich nicht über eine Referenz lädt:

%Vor%

G ++ tut dies absichtlich, denn wie im Handbuch angegeben ( Wann wird auf ein flüchtiges C ++ - Objekt zugegriffen? < (a)) Der Standard ist nicht klar darüber, was einen Zugriff auf ein flüchtiges qualifiziertes Objekt ausmacht. Wie dort angegeben, müssen Sie die lvalue-to-rvalue-Konvertierung erzwingen, um eine Last von einem volatilen zu erzwingen.

Clang gibt Warnungen im C ++ 03-Modus, die eine ähnliche Interpretation anzeigen:

%Vor%

Das G ++ - Verhalten und das GCC-Handbuch scheinen für C ++ 03 korrekt zu sein, aber es gibt einen Unterschied in C ++ 11 relativ zu C ++ 03, eingeführt durch DR 1054 (was auch erklärt, warum Clang sich in C ++ anders verhält) 3 und C ++ 11 Modi). 5 [expr] p10 definiert einen -Wertausdruck und besagt, dass für flüchtige Elemente die lvalue-to-rvalue-Konvertierung auf einen id-Ausdruck angewendet wird em> wie Ihre Anweisungen A und C. Die Spezifikation für lvalue-to-rvalue-Konvertierung (4.1 [conv.lval]) sagt, dass das Ergebnis der Wert des glvalue ist, der einen Zugriff des flüchtigen darstellt. Nach 5p10 sollte auf alle drei Ihrer Aussagen zugegriffen werden, daher muss G ++ 's Handhabung der Anweisung C aktualisiert werden, um C ++ 11 zu entsprechen. Ich habe es als Ссылка

gemeldet     
Jonathan Wakely 27.11.2013 13:26
quelle
3

Dieses gcc Dokument 7.1 Wann wird auf ein flüchtiges C ++ Objekt zugegriffen? ist hier relevant , und ich zitiere ( Betonung meiner Zukunft ):

  

Der C ++ - Standard unterscheidet sich vom C-Standard in der Behandlung von flüchtigen Objekten. Es wird nicht angegeben, was einen flüchtigen Zugriff ausmacht , außer zu sagen, dass C ++ sich in Bezug auf flüchtige Substanzen ähnlich wie C verhalten sollte

     

Die C- und C ++ - Sprachspezifikationen unterscheiden sich, wenn auf ein Objekt in einem leeren Kontext zugegriffen wird:

und liefert dieses Beispiel:

%Vor%

und fährt fort mit:

  

Der C ++ - Standard gibt an, dass solche Ausdrücke keiner lvalue to rvalue-Konvertierung unterzogen werden und dass der Typ des dereferenzierten Objekts möglicherweise unvollständig ist. Der C ++ - Standard gibt nicht explizit an, dass es sich um eine Lvalue to rvalue-Konvertierung handelt, die dafür verantwortlich ist, einen Zugriff zu verursachen.

Dies sollte sich auf den Standardentwurfsabschnitt 5.3.1 Unäre Operatoren Absatz 1 beziehen, der besagt:

  

Der unary * -Operator führt eine Indirektion aus: Der Ausdruck, auf den er angewendet wird, soll ein Zeiger auf einen Objekttyp oder ein Zeiger auf einen Funktionstyp sein, und das -Ergebnis ist ein lvalue , das auf das Objekt verweist oder Funktion, auf die der Ausdruck zeigt. [...]

und in Bezug auf Referenzen:

  

Wenn Sie einen Verweis auf volatile verwenden, behandelt G ++ keine äquivalenten Ausdrücke als Zugriffe auf flüchtige Elemente, sondern gibt stattdessen eine Warnung aus, dass auf flüchtige Elemente nicht zugegriffen wird. Der Grund dafür ist, dass es ansonsten schwierig wird zu bestimmen, wo ein flüchtiger Zugriff auftritt, und dass es nicht möglich ist, den Rückgabewert von Funktionen zu ignorieren, die flüchtige Referenzen zurückgeben. Erneut Wenn Sie einen Lesevorgang erzwingen möchten, müssen Sie den Verweis auf einen R-Wert anwenden.

Es scheint also, dass gcc sich dafür entscheidet, Verweise auf flüchtige anders zu behandeln, und um erzwingen einen Lesevorgang müssen Sie in einen rvalue , zum Beispiel:

%Vor%

erzeugt einen prvalue und damit eine lvalue to rvalue-Konvertierung aus dem Abschnitt 5.2.9 Statischer Cast :

  

Das Ergebnis des Ausdrucks static_cast (v) ist das Ergebnis der Konvertierung des Ausdrucks v in den Typ T. Wenn T ein lvalue-Referenztyp oder ein rvalue-Verweis auf den Funktionstyp ist, ist das Ergebnis ein lvalue; Wenn T eine rvalue-Referenz auf den Objekttyp ist, ist das Ergebnis ein xvalue; Andernfalls ist das Ergebnis ein prvalue.

Aktualisieren

Der C ++ 11 Standardentwurf fügt% hinzu co_de% Ausdrücke Absatz 11 welcher sagt:

  

In einigen Kontexten erscheint ein Ausdruck nur für seine Nebenwirkungen. Ein solcher Ausdruck wird als Ausdruck mit verworfenem Wert bezeichnet. Der Ausdruck wird ausgewertet und sein Wert wird verworfen. Die Standardkonvertierungen von Array zu Zeiger (4.2) und Funktion zu Zeiger (4.3) werden nicht angewendet. Die lvalue-to-rvalue-Konvertierung (4.1) wird nur dann angewendet, wenn der Ausdruck ein Lvalue des Typs Volatile-qualified ist und einer der folgenden Werte ist:

und beinhaltet:

  

- ID-Ausdruck (5.1.1),

Das erscheint mir mehrdeutig, denn in Bezug auf 5 und a; Sektion c; ist es ein 5.1.1 p8 und es ist nicht offensichtlich, dass es diesen Fall abdeckt, aber Jonathan fand DR 1054 sagt, dass es tatsächlich diesen Fall behandelt.

    
Shafik Yaghmour 27.11.2013 13:02
quelle