Ist der folgende Code in C ++ 11 zulässig?
%Vor%Der Code stammt aus der "C ++ Programmiersprache" 4. Ausgabe (Seite 150).
Wie wir wissen, ist die Eingrenzung der Konvertierung für die Listeninitialisierung nicht zulässig, und unter der Standarddefinition der Konvertierungseinschränkung haben wir:
Eine einschränkende Umwandlung ist eine implizite Umwandlung
- [...]
- Von einem Aufzählungstyp vom Typ Integer oder nicht aufgeschnitten zu einem Integer-Typ, der nicht alle Werte des ursprünglichen Typs darstellen kann, außer wenn die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Konvertierung in den Zieltyp passt und den ursprünglichen Wert erzeugt wenn zurück zum ursprünglichen Typ konvertiert wird.
Überprüfen Sie die Regel der Verringerung der Konvertierung gegen den Beispielcode, ich begründe, dass der Beispielcode illegal ist, weil 0xaabb
und 0xaaaabbbbccccdddd
nicht in int16_t
bzw. int64_t
dargestellt werden können. Ist das richtig?
Aber ich verstehe den Wortlaut nicht genau "außer, wo die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Umwandlung in den Zieltyp passt und den ursprünglichen Wert erzeugt, wenn zurück konvertiert wird der ursprüngliche Typ ". Ich frage mich, in welchem Szenario der tatsächliche Wert nach der Konvertierung nicht in den Zieltyp passen kann. Da Konvertierungen zwischen Integer-Typen immer gültig sind (obwohl die Implementierung für den Fall definiert ist, dass der Zieltyp signiert ist und der Quellwert nicht im Zieltyp dargestellt werden kann, aber trotzdem nicht undefiniert ist), gilt immer "der Wert nach der -Konvertierung passt in den Zieltyp "? Und von diesem Standpunkt aus beginne ich mein Urteil darüber in Frage zu stellen, dass der Beispielcode die Conversion einschränkt. Wenn das der Fall ist, warum gibt der Standard etwas immer in einer Bedingung wahr? Warum sage ich nicht einfach "außer, wo die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Konvertierung den ursprünglichen Wert erzeugt, wenn er wieder in den ursprünglichen Typ konvertiert wird"?
Kann mir jemand helfen, das zu klären? Danke!
Dies ist ein Fehler im Standard, siehe CWG-Problem 1449 . Der Text wurde in
geändertvon einem Integer-Typ oder nicht gekürzten Aufzählungstyp zu einem Integer-Typ, der nicht alle Werte des ursprünglichen Typs darstellen kann, außer wenn die Quelle ein konstanter Ausdruck ist, dessen Wert nach Integral-Promotions in den Zieltyp
passt
Hinweis: Der Status des Problems, DRWP, bedeutet, dass der Standard offiziell noch nicht geändert wurde, und es kann argumentiert werden, dass zumindest Ihr int64_t
-Beispiel in C ++ 11 legal ist. Compiler implementieren die neuen Regeln jedoch bereits, da dies bereits die beabsichtigte Bedeutung der ursprünglichen Formulierung war.
Schauen wir uns an, wie der Wert in eine vorzeichenbehaftete Ganzzahl konvertiert wird:
4.7 / 3 Wenn der Zieltyp signiert ist, ist der Wert unverändert, wenn er im Zieltyp (und der Bitfeldbreite) dargestellt werden kann. Andernfalls ist der Wert implementierungsdefiniert .
Diese Konvertierungen geben also implementierungsdefinierte Werte. Eine sinnvolle Implementierung wird die Umwandlung definieren, um den entsprechenden negativen Wert für dieses Bitmuster zu erhalten, der in den Zieltyp passt.
Die Frage ist also, ob die Konvertierung zurück zum Typ des Literals den Wert erhält? Dies hängt von der implementierungsdefinierten Größe der Literaltypen ab. Die erste wird den Wert beibehalten, wenn int
genau 16 Bits hat, aber nicht, wenn es größer ist (in diesem Fall wird 0xaabb
signiert, und die Umwandlung ergibt einen negativen Wert). Gleichermaßen behält die Sekunde den Wert bei, wenn entweder int
genau 64 Bits hat oder int
kleiner ist und long long
genau 64 Bits hat.
Fazit: Es kommt darauf an. Auf einer typischen aktuellen Plattform mit 32-Bit int
und 64-bit long long
wird die erste schmaler und die zweite nicht. Der GCC stimmt zu und gibt eine Warnung mit -pedantic
aus.
Tags und Links c++ c++11 language-lawyer