Widziałem kod C ++ taki jak poniżej z wieloma typedef
s.
Jakie są korzyści z używania wielu typedef
takich jak ta w porównaniu do używania prymitywów C ++? Czy istnieje inne podejście, które może również przynieść te korzyści?
Ostatecznie wszystkie dane są przechowywane w pamięci lub przesyłane przewodowo jako bity i bajty, czy to naprawdę ma znaczenie?
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;
Logiczne wydaje się staranie, aby upewnić się, że ten sam typ jest zawsze używany do konkretnej rzeczy, aby uniknąć przepełnienia, ale często widzę kod, w którym zamiast tego „int” był używany wszędzie. typedef
Ing często nie prowadzi do kodu, który wygląda trochę jak ten jednak:
DoSomething(EscalationLevel escalationLevel) {
...
}
Co sprawia, że zastanawiam się, który token tak naprawdę opisuje parametr: typ parametru lub nazwa parametru?
c++
data-structures
znak
źródło
źródło
Minute
do funkcji, której argument został zadeklarowany jako typSecond
.Odpowiedzi:
Nazwa parametru powinna opisywać, co to znaczy - w twoim przypadku poziom eskalacji. Typ jest reprezentowany przez wartość - dodanie typedefs, jak w twoim przykładzie, zaciemnia tę część sygnatury funkcji, więc nie polecałbym tego.
Typedefs są przydatne w przypadku szablonów lub jeśli chcesz zmienić typ używany dla niektórych parametrów, na przykład podczas migracji z platformy 32-bitowej na platformę 64-bitową.
źródło
int32_t
to, że musisz upewnić się, że są poprawne podczas kompilacji na różnych platformach. Jeśli spodziewaszIdentity
się zmiany zakresu w pewnym momencie, myślę, że wolałbym dokonywać zmian bezpośrednio we wszystkich kodach, których dotyczy problem. Ale nie jestem pewien, ponieważ musiałbym wiedzieć więcej o twoim konkretnym projekcie. Być może zechcesz uczynić z tego osobne pytanie.Na początku myślałem „dlaczego nie”, ale potem przyszło mi do głowy, że jeśli będziesz dążył do takich długości, aby oddzielić takie typy, lepiej wykorzystaj język. Zamiast używać aliasów, faktycznie zdefiniuj typy:
Nie ma różnicy w wydajności między:
i:
masz również zalety dodania sprawdzania poprawności parametrów i bezpieczeństwa typu. Na przykład rozważ kod, który dotyczy pieniędzy za pomocą prymitywnych typów:
Oprócz problemów z zaokrąglaniem umożliwia także dowolny typ, który można przekształcić w liczbę zmiennoprzecinkową:
W tym przypadku nie jest to wielka sprawa, ale niejawne konwersje mogą być źródłem błędów, które trudno ustalić. Użycie a
typedef
nie pomaga tutaj, ponieważ są one jedynie aliasem typu.Użycie nowego typu całkowicie oznacza, że nie ma żadnych niejawnych konwersji, chyba że kodujesz operatora rzutowania, co jest złym pomysłem, ponieważ pozwala na niejawne konwersje. Możesz także enkapsulować dodatkowe dane:
Nic innego nie będzie pasować do tej funkcji, chyba że napiszemy kod, aby to się stało. Przypadkowe konwersje są niemożliwe. Możemy również pisać bardziej złożone typy w razie potrzeby bez większych problemów.
źródło
BOOST_STRONG_TYPEDEF
;)Użycie typedefs dla takich prymitywnych typów przypomina bardziej kod w stylu C.
W C ++ otrzymasz interesujące błędy, gdy tylko spróbujesz przeładować funkcje dla, powiedzmy,
EventLevel
iHour
. To sprawia, że dodatkowe nazwy typów są dość bezużyteczne.źródło
My (w naszej firmie) często to robimy w C ++. Pomaga zrozumieć i utrzymywać kod. Co jest dobre, gdy przenosisz ludzi między zespołami lub przeprowadzasz refaktoryzację. Przykład:
Uważamy, że dobrą praktyką jest tworzenie typedef do nazwy wymiaru na podstawie typu reprezentacji. Ta nowa nazwa reprezentuje ogólną rolę w oprogramowaniu. Nazwa parametru jest rolą lokalną . Podobnie jak w
User sender, User receiver
. W niektórych miejscach może to być zbędne,void register(User user)
ale nie uważam tego za problem.Później można mieć pomysł, że
float
nie jest najlepszy do reprezentowania cen ze względu na specjalne zasady zaokrąglania rezerwacji, więc pobiera się lub implementujeBCDFloat
typ (dziesiętnie kodowany binarnie) i zmienia typedef. Nie ma wyszukiwania i zamiany pracy odfloat
doBCDFloat
których będzie utwardzana przez fakt, że istnieje prawdopodobnie wiele innych pływaków w kodzie.Nie jest to srebrna kula i ma swoje własne zastrzeżenia, ale uważamy, że lepiej jest z niej korzystać niż nie.
źródło
BOOST_STRONG_TYPEDEF(float, Price)
, ale nie posunąłbym się tak daleko w przypadku przeciętnego projektu. A może chciałbym. Muszę na tym spać. :-)typedef
w zasadzie pozwala ci podać alias dlatype
.Daje to elastyczność unikania
type names
wielokrotnego wpisywania długich znaków i uczynieniatype
ich łatwiejszymi do odczytania, w których nazwa aliasu wskazuje zamiar lub celtype
.Jest bardziej kwestią wyboru, jeśli chcesz mieć bardziej czytelne nazwy
typedef
w swoim projekcie.Zwykle unikam używania
typedef
prymitywnych typów, chyba że są one wyjątkowo długie do wpisania. Moje nazwy parametrów są bardziej orientacyjne.źródło
Nigdy bym tego nie zrobił. Upewnienie się, że wszystkie mają ten sam rozmiar, to jedno, ale wtedy musisz tylko nazywać je integralnymi typami.
źródło
Używanie takich typedefów jest w porządku, o ile ktokolwiek z nich skorzysta , nie musi nic wiedzieć o ich podstawowej reprezentacji . Na przykład, jeśli chcesz przekazać
PacketLength
obiekt do któregokolwiekprintf
lubscanf
, musisz znać jego rzeczywisty typ, aby wybrać odpowiedni specyfikator konwersji. W takich przypadkach typedef dodaje poziom zaciemnienia bez kupowania czegokolwiek w zamian; równie dobrze mógłbyś właśnie zdefiniować obiekt jakoint32_t
.Jeśli chcesz wymusić semantykę specyficzną dla każdego typu (np. Dopuszczalne zakresy lub wartości), lepiej jest stworzyć abstrakcyjny typ danych i funkcje do działania na tym typie, niż tylko utworzyć typedef.
źródło