Meine Forschung hat dazu noch keine Antwort gefunden (in SOF), aber ich bin mir sicher, dass es irgendwo zuvor gefragt worden sein muss, wenn es so ist.
Ich habe einen Aufzählungstyp in C ++ erstellt und dann einen Wert aus einer Nachrichtenkopfzeile eingelesen und möchte ihn in einer Variablen meines Aufzählungstyps speichern, Beispiel:
%Vor% Also, dieser Code kompiliert nicht in C ++, weil er das int nicht in myNum_t umwandeln kann. Also, wenn ich es myNum = (myNum_t) getMessageNumType();
einspiele, kompiliert das natürlich jetzt. Aber macht es das Richtige? Was passiert, wenn der zurückgegebene Wert außerhalb des Bereichs von myNum_t liegt? Gibt es hier eine "Best Practice", die ich vermisse?
Aber macht es das Richtige?
Angenommen, der Wert ist für den Aufzählungstyp gültig, ja.
Was passiert, wenn der zurückgegebene Wert außerhalb des Bereichs von myNum_t liegt?
Kommt darauf an.
Bis (und ausschließlich) der nächsten Potenz von Zwei erhalten Sie garantiert genau diesen Wert. Was dein Code dann damit macht, bleibt dir überlassen. Mit anderen Worten: (int)(myNumType_t)7
ist mit Ihrem Code garantiert gleich 7. Dies ist wichtig, da einige Leute bitweise Operationen für Aufzählungswerte verwenden. Wenn eine Aufzählung BIT0 = 1, BIT1 = 2, BIT2 = 4
hat, ist BIT0 | BIT1 | BIT2
gemeint in demselben Aufzählungstyp gespeichert.
Bei größeren Werten kann nicht viel verwendet werden. Bei einigen Implementierungen wird Ihre Enumeration in einem einzelnen (8-Bit-) Byte gespeichert. Bei diesen Implementierungen kann (int)(myNumType_t)257
also möglicherweise nicht gleich 257 sein. Bei anderen ist dies möglicherweise der Fall. Sie sollten das besser vermeiden, indem Sie vorher den ganzzahligen Wert überprüfen.
Die erste Frage ist, ob Sie der Quelle des Wertes trauen können oder nicht, und im Allgemeinen, wenn Sie Nachrichten aus dem Netzwerk oder einem anderen Ein- / Ausgabegerät lesen, würde ich dieses Vertrauen in Frage stellen.
Wenn Sie ihm nicht vertrauen können, sollten Sie in der Lage sein, eine kleine Funktion zu schreiben, die den empfangenen Wert testet und sie dem entsprechenden Enumerator zuordnet oder ausfällt, wenn der Wert außerhalb des gültigen Bereichs liegt. Beachten Sie, dass der Compiler in dem von Ihnen bereitgestellten Beispielcode einen beliebigen Typ für die Aufzählung auswählen konnte, der alle Werte im Bereich von 0-7 darstellen konnte. Der Standard gibt keine zusätzlichen Garantien.
Während der Compiler in der Praxis wahrscheinlich einen größeren Typ wie int
für diesen speziellen Fall auswählt, kann der Compiler davon ausgehen, dass der Wert nicht außerhalb dieses Bereichs liegt. Wenn der von der Nachricht dekodierte Wert größer als 8 ist, treffen Sie ein undefiniertes Verhalten und Sie erhalten möglicherweise Ergebnisse, die Sie nicht wirklich erwarten.
Für ein praktisches Beispiel, wenn die Enumeratoren von 0 bis 3 reichen, enthalten beide, und Sie hatten diesen Code:
%Vor% Dem Compiler ist es erlaubt, den default
-Fall zu entfernen, da alle Werte, die in enum_t
dargestellt werden können, explizit in switch
aufgelistet sind, so dass der default:
-Fall in einem wohlgeformten Programm nicht getroffen werden kann . Der Optimierer kann diesen Test folgendermaßen ändern:
Und Sie könnten am Ende überrascht sein, warum alle Werte gültig sind, selbst wenn Ihr Testfall Nachrichten mit ungültigen Werten sendet!
Die einzige wirklich sichere Int-zu-Enum-Umwandlung besteht darin, ALLE Fälle in der Enum- und der Fehlerprüfung abzudecken, dass die Eingabe möglicherweise zurückkehrt und Grenzerfassungen enthält, wenn die Möglichkeit besteht, dass der Bereich verlassen oder ein ungültiger Wert zurückgegeben wird und dann den schlechten Wert anmutig behandeln.
Wenn die Enumeration garantiert ein zusammenhängender Bereich ist, ist es etwas einfacher:
%Vor%Ja, es ist sicher, von int-Typ zu enumeration-Typ zu konvertieren.
§ 4.5 Integrale Werbung
Ein Prvalue eines nicht gekapselten Enumerationstyps, dessen zugrunde liegender Typ fest ist (7.2), kann in einen prvalue des zugrunde liegenden Typs konvertiert werden. Darüber hinaus kann , wenn eine integrale Heraufstufung auf den zugrunde liegenden Typ angewendet werden kann, ein prvalue eines nicht gekürzten Enumerationstyps, dessen zugrunde liegender Typ fest ist, in einen prvalue des heraufgestuften zugrunde liegenden Typs konvertiert werden.
Geben Sie einfach den Aufzählungstyp zurück, damit Sie Probleme mit dem Überspielen vermeiden können:
%Vor% Sie können einen Cast verwenden, um einen Integer-Wert in eine Enumeration zu konvertieren. Wenn Sie das tun, müssen Sie sicherstellen, dass der resultierende Wert aussagekräftig ist. Im Beispielcode sollten Sie sicherstellen, dass getMessageNumType()
einen geeigneten Wert zurückgibt.
In einem Aufzählungstyp gespeicherte Werte sind nicht auf die von den Aufzählern angegebenen Werte beschränkt. Zum Beispiel ist es üblich, einen Enumerator zusammen mit geeigneten überladenen Operatoren zu verwenden, um eine Bitmaske zu implementieren:
%Vor% Dieser |
Operator sollte wirklich mit einem überladenen Operator gemacht werden; Das habe ich der Einfachheit halber weggelassen. Die Besetzung ist in Ordnung, aber es wird mühsam, überall zu schreiben.
Tags und Links enumeration c++ casting