Я видел код C ++, такой как следующий со многими typedef
s.
Каковы преимущества использования многих typedef
подобных s по сравнению с использованием примитивов C ++? Есть ли другой подход, который также может обеспечить эти преимущества?
В конце концов, все данные хранятся в памяти или передаются по проводам в виде битов и байтов, это действительно имеет значение?
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;
Кажется логичным попытаться убедиться, что один и тот же тип всегда используется для определенной вещи, чтобы избежать переполнения, но я часто вижу код, в котором вместо этого просто используется int. typedef
ИНГ часто действительно приводит к коду , который выглядит немного как это , хотя:
DoSomething(EscalationLevel escalationLevel) {
...
}
Что тогда заставляет меня задуматься, какой токен на самом деле описывает параметр: тип параметра или имя параметра?
источник
Minute
, функцию в аргумент, объявленный как типSecond
.Ответы:
Имя параметра должно описывать, что оно означает - в вашем случае уровень эскалации. Тип представляет собой то, как представлено значение - добавление typedefs, как в вашем примере, запутывает эту часть сигнатуры функции, поэтому я бы не рекомендовал ее.
Typedefs полезны для шаблонов, или если вы хотите изменить тип, используемый для определенных параметров, например, при миграции с 32-битной на 64-битную платформу.
источник
int32_t
то, что вы должны убедиться, что они верны при компиляции на разных платформах. Если вы ожидаете, что диапазонIdentity
изменится в какой-то момент, я думаю, что я бы предпочел вносить изменения непосредственно во весь затронутый код. Но я не уверен, потому что мне нужно знать больше о вашем конкретном дизайне. Возможно, вы захотите сделать это отдельным вопросом.Сначала я подумал «почему бы и нет», но потом мне пришло в голову, что если вы собираетесь пойти на такую длину, чтобы разделить подобные типы, то лучше используйте язык. Вместо использования псевдонимов, на самом деле определяем типы:
Нет разницы в производительности между:
и:
у вас также есть преимущества добавления проверки параметров и безопасности типов. Например, рассмотрим код, который имеет дело с деньгами, используя примитивные типы:
Помимо проблем округления, он также позволяет любой тип, который может быть преобразован в число с плавающей точкой:
В этом случае это не имеет большого значения, но неявные преобразования могут стать источником ошибок, которые трудно определить. Использование здесь
typedef
не помогает, так как они являются просто псевдонимом типа.Использование нового типа полностью означает, что не существует неявных преобразований, если вы не кодируете оператор приведения, что является плохой идеей, особенно потому, что оно допускает неявные преобразования. Вы также можете инкапсулировать дополнительные данные:
Ничто другое не поместится в эту функцию, если мы не напишем код, чтобы это произошло. Случайные преобразования невозможны. Мы также можем написать более сложные типы по мере необходимости без особых хлопот.
источник
BOOST_STRONG_TYPEDEF
самом деле;)Использование typedef для таких примитивных типов больше похоже на код в стиле C.
В C ++ вы получите интересные ошибки, как только вы попытаетесь перегрузить функции, скажем,
EventLevel
иHour
. Это делает лишние имена типов довольно бесполезными.источник
Мы (в нашей компании) много делаем на C ++. Это помогает понять и поддерживать код. Что хорошо при перемещении людей между командами или проведении рефакторинга. Пример:
Мы считаем, что хорошей практикой является создание typedef для имени измерения из типа представления. Это новое имя представляет общую роль в программном обеспечении. Имя параметра является локальной ролью . Как в
User sender, User receiver
. В некоторых местах это может быть избыточно,void register(User user)
но я не считаю это проблемой.Позже у кого-то может возникнуть идея, что
float
не лучше всего представлять цены из-за специальных правил округления бронирования, поэтому вы загружаете или реализуетеBCDFloat
(двоично-десятичный) тип и изменяете typedef. Там нет поиска и замены работы сfloat
наBCDFloat
который будет закаленным тем , что есть , возможно , еще много плавает в вашем коде.Это не серебряная пуля и имеет свои предостережения, но мы думаем, что гораздо лучше ее использовать, чем нет.
источник
BOOST_STRONG_TYPEDEF(float, Price)
, но я бы не пошел так далеко в среднем проекте. Или, может быть, я бы. Я должен спать на нем. :-)typedef
в основном позволяет дать псевдоним дляtype
.Это дает вам гибкость, позволяя вам не вводить long
type names
снова и снова и делать ваш текстtype
более читабельным, в котором псевдоним указывает на намерение или цельtype
.Это больше вопрос выбора, если вы хотите, чтобы
typedef
в вашем проекте было больше читаемых имен .Обычно я избегаю использования
typedef
примитивных типов, если только они не слишком длинные для типирования. Я держу свои имена параметров более показательными.источник
Я бы никогда так не поступил. Убедиться в том, что все они имеют одинаковый размер, - это одно, но вам нужно только ссылаться на них как на целочисленные типы.
источник
Использование typedefs, как это нормально, до тех пор, пока тот, кто их использует , не должен ничего знать об их базовом представлении . Например, если вы хотите передать
PacketLength
объект одномуprintf
илиscanf
, вам нужно знать его фактический тип, чтобы вы могли выбрать правильный спецификатор преобразования. В подобных случаях typedef просто добавляет уровень запутывания, не покупая ничего взамен; с тем же успехом вы могли просто определить объект какint32_t
.Если вам нужно применить семантику, специфичную для каждого типа (например, допустимые диапазоны или значения), лучше создать абстрактный тип данных и функции для работы с этим типом, а не просто создавать определение типа.
источник