Допустимое использование typedef?

У меня есть char (т.е. байтовый) буфер, который я отправляю по сети. В какой-то момент в будущем я, возможно, захочу переключить буфер на другой тип, например unsigned char или short. Я думал о том, чтобы сделать что-то вроде этого:

typedef char bufferElementType;

И всякий раз, когда я что-то делаю с элементом буфера, я объявляю его как bufferElementType, а не как char. Таким образом, я мог бы переключиться на другой тип, изменив этот typedef (конечно, это было бы не так просто, но по крайней мере было бы легко определить места, которые нужно изменить ... рядом будет bufferElementType) .

Это правильное / хорошее использование typedef? Разве это не стоит хлопот? Будет ли у меня когда-нибудь в будущем головная боль? Это заставит меня ненавидеть программистов?

Я прочитал Когда следует использовать Typedef в C ++, но на самом деле никто об этом не рассказывал.


person drby    schedule 24.02.2009    source источник
comment
Вы используете массивы этого типа для своих буферов? Или вы имеете в виду, что буфер имеет длину 1 байт и в будущем вы можете сделать его 2 или 4 байта?   -  person j_random_hacker    schedule 24.02.2009
comment
В этом случае нет большого преимущества в использовании typedef char bufferElementType ;. Если вы везде используете один и тот же размер массива, может быть полезно определить тип всего массива: typedef char [1024] bufferElementType; - что позволяет вам изменять размер буфера повсюду за один раз.   -  person j_random_hacker    schedule 24.02.2009
comment
Если, однако, ваши буферы действительно предназначены для хранения текстовых символов и вы рассматриваете возможность перехода с кодировки символов размером точно 1 байт (например, ANSI) на кодировку символов размером точно 2 или точно 4 байта, то ваш исходный typedef является путь идти.   -  person j_random_hacker    schedule 24.02.2009
comment
Есть один буфер этого типа, но я также выполняю операции с байтами / символами, которые связаны с буфером (и имеют разную длину массива). На данный момент у меня есть константа для длины буфера, поэтому я могу изменить ее вместе с типом.   -  person drby    schedule 24.02.2009
comment
Я имею в виду следующее: если буфер существует только для хранения x байтов, какое преимущество может быть в изменении типа этого хранилища? Если вы ничего не делаете с буфером, зависящим от типа, не имеет значения, какой он тип. Обычно используется char, потому что он позволяет создавать буферы любого размера.   -  person j_random_hacker    schedule 24.02.2009
comment
... (В отличие от любого большего типа, который потребовал бы, чтобы размер буфера был кратен размеру этого типа в байтах, и, вероятно, вводил бы ограничения выравнивания.) IMHO buffers-of-a-fixed-size-in-bytes - это одно из тех немногих случаев, когда нет никакого преимущества от использования typedef :)   -  person j_random_hacker    schedule 24.02.2009


Ответы (3)


Это отличное (и нормальное) использование. Однако вы должны быть осторожны, чтобы, например, выбранный вами тип соответствовал одним и тем же критериям со знаком / без знака или чтобы они одинаково реагировали на операторы. Тогда было бы проще потом поменять тип.

Другой вариант - использовать шаблоны, чтобы не фиксировать тип до момента компиляции. Класс, который определяется как:

template <typename CharType>
class Whatever
{
   CharType aChar;
   ...
};

может работать с любым выбранным вами типом символов, при этом он одинаково реагирует на все операторы.

person Diego Sevilla    schedule 24.02.2009
comment
Я не понимаю, какие преимущества дает использование typedef в этом случае. Единственное назначение переменной buffer - предоставить заданное количество байтов памяти, а char всегда является размером наименьшей адресуемой единицы хранения. Можете ли вы дать сценарий, в котором было бы полезно изменить typedefed? - person j_random_hacker; 24.02.2009
comment
char в wchar, например; char в XMLChar (libxml2) и т. д. Я понимаю, что случай с единственным символом не самый интересный, но присвоение семантически описывающих имен типов также является хорошей практикой, помимо других причин, которые я привел. - person Diego Sevilla; 24.02.2009
comment
Да, это один из вариантов использования. У меня возникло ощущение от вопроса спрашивающего, что его интересует буфер размером байтов, но если он должен содержать текстовые символы в некоторой (фиксированного размера, но, возможно, многобайтовой) кодировке, тогда уместно рассмотреть различные типы буферных элементов. - person j_random_hacker; 24.02.2009

Еще одно преимущество typedef в том, что при разумном использовании они могут повысить удобочитаемость. В качестве действительно глупого примера, метр и градус могут быть двойными, но вы хотели бы различать их. Использование typedef - это быстрое и простое решение, позволяющее сделать ошибки более заметными.

Примечание: более надежным решением для приведенного выше примера было бы создание разных типов для метра и градуса. Таким образом, компилятор может сам обеспечивать соблюдение требований. Это требует небольшой работы, которая, однако, не всегда окупается. Использование typedefs - это быстрый и простой способ сделать ошибки видимыми, как описано в статье, указанной выше.

person Gilad Naor    schedule 24.02.2009
comment
typedef определенно может повысить удобочитаемость, однако они не могут сделать ошибки более заметными, поскольку это просто псевдонимы, которые компилятор немедленно преобразует в их базовый тип. Итак, если оба типа Meter и Degree заданы двойным типом, код Meter x; Степень y; х = у; компилируется без ошибок. - person j_random_hacker; 24.02.2009
comment
Я никогда не утверждал обратного. Гораздо лучше, если компилятор сможет обеспечить это сам. Но для этого требуется больше кода. Быстрое и простое решение - сделать его видимым для ЛЮДЕЙ - подробнее см. В связанной статье. - person Gilad Naor; 24.02.2009
comment
Справедливо. Вы можете избежать случайного прямого присвоения типов с помощью class Meter {double _x; общедоступный: Счетчик (двойной x): _x (x) {}; оператор двойной & () {return _x; }}; и то же самое для степени; но это все еще позволяет, например, Метр x; Степень y; х = у + 5 ;. Этого также можно избежать, но это сложнее. - person j_random_hacker; 24.02.2009
comment
(FTR Я удалил два предыдущих комментария, которые были не очень хорошо продуманными ... Для защиты от x = y + 5; вам необходимо определить перегрузки операторов для каждого оператора, чтобы он оставался в типе как можно дольше. Это много работы, даже больше, если вы хотите сохранить типы и во всех библиотечных функциях.) - person j_random_hacker; 24.02.2009

Да, это идеальное использование typedef, по крайней мере, в C.

Для C ++ можно утверждать, что шаблоны - лучшая идея (как предложил Диего Севилья), но у них есть свои недостатки. (Дополнительная работа, если все, что использует этот тип данных, еще не заключено в несколько классов, более медленное время компиляции и более сложная структура исходного файла и т. Д.)

Также имеет смысл объединить два подхода, то есть дать имя typedef параметру шаблона.

Обратите внимание, что при отправке данных по сети char и другие целочисленные типы могут не быть взаимозаменяемыми (например, из-за порядка байтов). В этом случае использование шаблонного класса со специализированными функциями может иметь больше смысла. (send ‹char› отправляет байт, send ‹short› сначала преобразует его в сетевой порядок байтов)

Еще одно решение - создать класс BufferElementType со вспомогательными методами (convertToNetworkOrderBytes ()), но я уверен, что это будет излишним для вас.

person aib    schedule 24.02.2009