Was ist die Bedeutung der speziellen Sprache im Standard für lvalue-to-rvalue Konvertierungen für vorzeichenlose Zeichenarten mit unbestimmtem Wert

8

Im C ++ 14-Standard (n3797) lautet der Abschnitt für lvalue to rvalue-Konvertierungen wie folgt (Hervorhebung von mir):

  

4.1 Lvalue-to-rvalue-Konvertierung [conv.lval]

     
  1. Ein glvalue (3.10) eines Nicht-Funktions-Array-Typs T kann in einen prvalue konvertiert werden. Wenn T ein unvollständiger Typ ist, wird ein Programm, das diese Konvertierung erfordert, schlecht gebildet. Wenn T ein Nicht-Klassentyp ist, ist der Typ des Prvalue die cv-unqualifizierte Version von T . Ansonsten ist der Typ des prvalue T .

  2.   
  3. Wenn eine Lvalue-to-rvalue-Konvertierung in einem nicht evaluierten Operanden auftritt   oder ein Unterausdruck davon (Klausel 5) der in der   auf das referenzierte Objekt wird nicht zugegriffen. In allen anderen Fällen ist das Ergebnis der   Die Konvertierung wird gemäß den folgenden Regeln festgelegt:

         
    • Wenn T eine (möglicherweise cv-qualifizierte) std::nullptr_t ist, dann ist das Ergebnis eine Null-Zeiger-Konstante.
    •   
    • Andernfalls, wenn T über einen Klassentyp verfügt, initialisiert die Konvertierungskopie ein temporäres vom Typ T aus dem glvalue und das Ergebnis der Konvertierung ist ein prvalue für das temporäre.
    •   
    • Andernfalls, wenn das Objekt, auf das der glvalue verweist, einen ungültigen Zeigerwert enthält, ist das Verhalten implementierungsdefiniert.
    •   
    • Andernfalls, wenn T ein (möglicherweise cv-qualifizierter) unsignierter Zeichentyp ist und das Objekt, auf das der glvalue verweist, einen unbestimmten Wert enthält und dieses Objekt keine automatische Speicherdauer hat oder der glvalue war der Operand eines unären & -Operators oder er war an eine Referenz gebunden, das Ergebnis ist ein unspezifizierter Wert.
    •   
    • Andernfalls, wenn das Objekt, auf das sich der glvalue bezieht, einen unbestimmten Wert hat, ist das Verhalten nicht definiert.
    •   
    • Andernfalls ist das vom glvalue angegebene Objekt das Prvalue-Ergebnis.
    •   
  4.   
  5. [ Hinweis: Siehe auch 3.10]
  6.   

Was ist die Bedeutung dieses Absatzes (in Fettdruck)?

Wenn dieser Absatz nicht hier wäre, würden die Situationen, in denen er angewendet wird, zu undefiniertem Verhalten führen. Normalerweise würde ich erwarten, dass der Zugriff auf einen unsigned char -Wert, während er einen unbestimmten Wert hat, zu undefiniertem Verhalten führt. Aber mit diesem Absatz bedeutet das,

  • Wenn ich nicht wirklich auf den Zeichenwert zugreife, d. h. ich gebe ihn sofort an & weiter oder verbinde ihn mit einer Referenz oder
  • Wenn die unsigned char keine automatische Speicherdauer hat,

dann ergibt die Umwandlung einen unspezifizierten Wert und kein undefiniertes Verhalten.

Bin ich richtig zu dem Schluss, dass dieses Programm:

%Vor%

ist vom Standard gut definiert und muss eine Sequenz von 500 nicht spezifizierten Ints ausgeben, während das gleiche Programm, in dem T = int , ein undefiniertes Verhalten hat?

IIUC, einer der Gründe, um es UB zu machen, Dinge mit unbestimmten Werten zu lesen, besteht darin, eine aggressive totale Speichereliminierung durch den Optimierer zuzulassen. Dieser Absatz kann also bedeuten, dass ein kompilierender Compiler nicht so viel Optimierung durchführen kann, wenn er mit unsigned char oder Arrays von unsigned char arbeitet.

Wenn ich richtig verstehe, was ist der Grund für diese Regel? Wann ist es nützlich, unsigned char lesen zu können, die unbestimmte Werte haben und nicht spezifizierte Ergebnisse anstelle von UB erhalten? Ich habe das Gefühl, dass, wenn sie sich so viel Mühe geben, diesen Teil der Regel zu erstellen, sie motiviert waren, bestimmten Codebeispielen zu helfen, die ihnen wichtig waren, oder mit einem anderen Teil des Standards konsistent zu sein oder ein anderes Problem zu vereinfachen . Aber ich habe keine Ahnung, was das sein könnte.

    
Chris Beck 06.09.2017, 01:10
quelle

1 Antwort

1

In vielen Situationen wird Code einige Teile eines PODS oder Arrays schreiben, ohne alles zu schreiben, und dann Funktionen wie memcpy oder fwrite verwenden, um das gesamte Ding zu kopieren oder zu schreiben, ohne Rücksicht darauf, welche Teile Werte zugewiesen hatten und welche nicht. Obwohl es für C ++ - Code nicht sehr üblich ist, bytebasierte Operationen zu verwenden, um den Inhalt von Aggregaten zu kopieren oder zu schreiben, ist die Fähigkeit, dies zu tun, ein grundlegender Teil der Sprache. Die Forderung, dass ein Programm bestimmte Werte in alle Teile eines Objekts schreibt, einschließlich derjenigen, für die sich niemals etwas "interessieren" wird, würde die Effizienz unnötig beeinträchtigen.

    
supercat 06.09.2017 16:36
quelle