Ich habe C ++ - Code wie den folgenden mit vielen typedef
s gesehen.
Was sind die Vorteile der Verwendung vieler typedef
s im Vergleich zur Verwendung von C ++ - Grundelementen? Gibt es einen anderen Ansatz, mit dem auch diese Vorteile erzielt werden könnten?
Am Ende werden alle Daten im Speicher gespeichert oder als Bits und Bytes über die Leitung übertragen. Ist das wirklich wichtig?
types.h:
typedef int16_t Version;
typedef int32_t PacketLength;
typedef int32_t Identity;
typedef int32_t CabinetNumber;
typedef int64_t Time64;
typedef int64_t RFID;
typedef int64_t NetworkAddress;
typedef int64_t PathfinderAddress;
typedef int16_t PathfinderPan;
typedef int16_t PathfinderChannel;
typedef int64_t HandsetSerialNumber;
typedef int16_t PinNumber;
typedef int16_t LoggingInterval;
typedef int16_t DelayMinutes;
typedef int16_t ReminderDelayMinutes;
typedef int16_t EscalationDelayMinutes;
typedef float CalibrationOffset;
typedef float AnalogValue;
typedef int8_t PathfinderEtrx;
typedef int8_t DampingFactor;
typedef int8_t RankNumber;
typedef int8_t SlavePort;
typedef int8_t EventLevel;
typedef int8_t Percent;
typedef int8_t SensorNumber;
typedef int8_t RoleCode;
typedef int8_t Hour;
typedef int8_t Minute;
typedef int8_t Second;
typedef int8_t Day;
typedef int8_t Month;
typedef int16_t Year;
typedef int8_t EscalationLevel;
Es scheint logisch, zu versuchen, sicherzustellen, dass für eine bestimmte Sache immer derselbe Typ verwendet wird, um Überläufe zu vermeiden, aber ich sehe häufig Code, in dem stattdessen "int" so ziemlich überall verwendet wurde. Das typedef
ing führt jedoch häufig zu Code, der ungefähr so aussieht:
DoSomething(EscalationLevel escalationLevel) {
...
}
Wodurch frage ich mich dann, welches Token den Parameter tatsächlich beschreibt: den Parametertyp oder den Parameternamen?
quelle
Minute
an eine Funktion zu übergeben, für die ein Argument als Typ deklariert wurdeSecond
.Antworten:
Der Name eines Parameters sollte beschreiben, was er bedeutet - in Ihrem Fall die Eskalationsstufe. Der Typ ist wie der Wert dargestellt wird - das Hinzufügen von typedefs wie in Ihrem Beispiel verschleiert diesen Teil der Funktionssignatur, daher würde ich es nicht empfehlen.
Typedefs sind nützlich für Vorlagen oder wenn Sie den für bestimmte Parameter verwendeten Typ ändern möchten, beispielsweise bei der Migration von einer 32-Bit- auf eine 64-Bit-Plattform.
quelle
int32_t
ist, dass Sie sicherstellen müssen, dass sie korrekt sind, wenn Sie auf verschiedenen Plattformen kompilieren. Wenn Sie erwarten, dass sich der Bereich vonIdentity
irgendwann ändert, würde ich es vorziehen, die Änderungen direkt in allen betroffenen Codes vorzunehmen. Ich bin mir jedoch nicht sicher, da ich mehr über Ihr spezielles Design wissen müsste. Vielleicht möchten Sie das zu einer separaten Frage machen.Zuerst dachte ich mir "Warum nicht", aber dann kam mir der Gedanke, dass man die Sprache besser nutzen sollte, wenn man sich so sehr bemüht, um die Typen so zu trennen. Anstatt Aliase zu verwenden, definieren Sie tatsächlich Typen:
Es gibt keinen Leistungsunterschied zwischen:
und:
und Sie haben auch die Vorteile einer zusätzlichen Parametervalidierung und Typensicherheit. Betrachten Sie beispielsweise Code, der sich mit Geld unter Verwendung primitiver Typen befasst:
Abgesehen von den Rundungsproblemen sind auch alle Typen möglich, die in ein Float konvertiert werden können:
In diesem Fall ist es keine große Sache, aber implizite Konvertierungen können eine Quelle von Fehlern sein, die schwer zu lokalisieren sind. Die Verwendung von a
typedef
hilft hier nicht weiter, da es sich lediglich um einen Typ-Alias handelt.Wenn Sie einen neuen Typ vollständig verwenden, gibt es keine impliziten Konvertierungen, es sei denn, Sie codieren einen Casting-Operator. Dies ist eine schlechte Idee, da implizite Konvertierungen zulässig sind. Sie können auch zusätzliche Daten einkapseln:
Nichts anderes wird in diese Funktion passen, es sei denn, wir schreiben Code, um dies zu ermöglichen. Versehentliche Umbauten sind ausgeschlossen. Wir können auch komplexere Typen nach Bedarf schreiben, ohne viel Aufwand.
quelle
BOOST_STRONG_TYPEDEF
eigentlich;)Die Verwendung von typedefs für solche primitiven Typen ähnelt eher dem C-Code.
In C ++ erhalten Sie interessante Fehler, sobald Sie versuchen, Funktionen für, sagen wir,
EventLevel
und zu überladenHour
. Das macht die zusätzlichen Typnamen ziemlich nutzlos.quelle
Wir (in unserer Firma) machen das oft in C ++. Es hilft, Code zu verstehen und zu pflegen. Das ist gut, wenn Leute zwischen Teams wechseln oder umgestalten. Beispiel:
Wir glauben, dass es eine gute Praxis ist, aus dem Darstellungstyp ein typedef für den Dimensionsnamen zu erstellen. Dieser neue Name repräsentiert eine allgemeine Rolle in einer Software. Der Name eines Parameters ist eine lokale Rolle . Wie in
User sender, User receiver
. An manchen Stellen kann es überflüssig sein,void register(User user)
aber ich sehe es nicht als Problem an.Später kommt man vielleicht auf die Idee, dass
float
die Darstellung von Preisen aufgrund der speziellen Rundungsregeln der Buchung nicht die beste istBCDFloat
. Daher lädt man einen Typ (binär codierte Dezimalzahl) herunter oder implementiert ihn und ändert den Typedef. Es gibt keine Such- und Ersetzungsarbeitfloat
,BCDFloat
die durch die Tatsache, dass möglicherweise viel mehr Gleitkommazahlen in Ihrem Code vorhanden sind, beeinträchtigt würde.Es ist keine Wunderwaffe und hat seine eigenen Vorbehalte, aber wir denken, dass es viel besser ist, es zu benutzen, als nicht.
quelle
BOOST_STRONG_TYPEDEF(float, Price)
, aber ich würde bei einem durchschnittlichen Projekt nicht so weit gehen. Oder vielleicht würde ich. Ich muss darauf schlafen. :-)typedef
Im Grunde können Sie einen Alias für eintype
.Es gibt Ihnen die Flexibilität, nicht
type names
immer wieder lange zu tippen und dietype
Lesbarkeit zu verbessern, wobei der Aliasname die Absicht oder den Zweck von angibttype
.Es ist eher eine Frage der Wahl, ob Sie mehr lesbare Namen
typedef
in Ihrem Projekt haben möchten .Normalerweise vermeide ich es,
typedef
primitive Typen zu verwenden, es sei denn, sie sind ungewöhnlich lang für die Eingabe. Ich halte meine Parameternamen indikativer.quelle
Ich würde so etwas niemals tun. Sicherzustellen, dass sie alle die gleiche Größe haben, ist eine Sache - aber Sie müssen sie dann nur als integrale Typen bezeichnen.
quelle
Die Verwendung solcher typedefs ist in Ordnung, solange derjenige, der sie verwendet, nichts über die zugrunde liegende Darstellung wissen muss . Wenn Sie beispielsweise ein
PacketLength
Objekt anprintf
oder übergeben möchtenscanf
, müssen Sie dessen tatsächlichen Typ kennen, damit Sie den richtigen Konvertierungsspezifizierer auswählen können. In solchen Fällen fügt der Typedef lediglich einen Grad an Verschleierung hinzu, ohne etwas dafür zu kaufen. Sie hätten das Objekt genauso gut definieren können alsint32_t
.Wenn Sie eine für jeden Typ spezifische Semantik erzwingen müssen (z. B. zulässige Bereiche oder Werte), sollten Sie einen abstrakten Datentyp und Funktionen für diesen Typ erstellen, anstatt nur einen Typedef zu erstellen.
quelle