Почему программисты C используют typedefs для переименования основных типов?
Итак, я далек от эксперта по C, но что-то беспокоило меня о коде, который я читал в течение длительного времени: может кто-нибудь объяснить мне, почему программисты C(++) используют typedefs для переименования простых типов? Я понимаю, почему вы будете использовать их для структур, но в чем именно причина объявлений, которые я вижу, как
typedef unsigned char uch;
typedef uch UBYTE;
typedef unsigned long ulg;
typedef unsigned int u32;
typedef signed short s16;
есть ли в этом какое-то преимущество, которое мне не ясно (программист, чей опыт начинается с Java и не рискнул далеко выйти за пределы строго типобезопасного языки)? Потому что я не могу придумать никакой причины для этого-похоже, что это просто сделает код менее читаемым для людей, незнакомых с проектом.
Не стесняйтесь обращаться со мной как с новичком, я честно знаю очень мало об этом, и, вероятно, есть вещи, которые я неправильно понял с самого начала. ;)
9 ответов:
переименование типов без изменения их открытой семантики / характеристик не имеет большого смысла. В вашем примере
typedef unsigned char uch; typedef unsigned long ulg;
относятся к этой категории. Я не вижу смысла, кроме как сделать более короткое имя.
но эти
typedef uch UBYTE; typedef unsigned int u32; typedef signed short s16;
- это совершенно другая история. Например,
s16
означает "подписанный 16-битный тип". Этот тип не обязательноsigned short
. Какой конкретный тип будет скрываться заs16
зависит от платформы. Программисты вводят этот дополнительный уровень косвенного именования, чтобы упростить поддержку нескольких платформ. Если на какой-то другой платформе подписанный 16-битный тип оказываетсяsigned int
, программист должен будет изменить только одно определение typedef.UBYTE
по-видимому, означает беззнаковый тип байта машины, который не обязательноunsigned char
.стоит отметить, что спецификация C99 уже предоставляет стандартную номенклатуру для интегральных типов определенной ширины, например
int16_t
,uint32_t
и так далее. Вероятно, имеет смысл придерживаться этого стандартного соглашения об именах на платформах, которые не поддерживают C99.
Это позволяет для удобоносимости. Например, вам нужен 32-разрядный целочисленный тип без знака. Какой стандартный тип это? Вы не знаете - это реализация определена. Вот почему ты
typedef
отдельный тип должен быть 32-разрядным целым числом без знака и использовать новый тип в коде. Когда вам нужно скомпилировать на другой реализации, вы просто изменитеtypedef
s.
иногда он используется для уменьшения громоздкой вещи, как
volatile unsigned long
к чему-то более компактному, напримерvuint32_t
.в других случаях это помогает с переносимостью, так как типы, такие как
int
не всегда одинаковы на каждой платформе. С помощью typedef вы можете установить класс хранения, который вас интересует, в ближайшее соответствие платформы без изменения всего исходного кода.
Ниже приводится цитата из языка программирования C (K&R)
помимо чисто эстетических вопросов, есть две основные причины для использования оператор typedef.
во-первых-для параметризации программы
во-первых, чтобы параметризовать программу против проблем переносимости. Если типов используются типы данных это может быть зависимым от машины, только у типов, нужно меняться, когда программа перемещается.
одной из распространенных ситуаций является использование typedef имен для различных целых количества, после этого делают соотвествующее набор вариантов short, int и long для каждой главной машины. типы, как типы size_t и ptrdiff_t из стандартной библиотеки примеры.
выделенные курсивом части говорят нам, что программисты
typedef
основной тип для переносимости. Если я хочу убедиться, что моя программа работает на разных платформах, используя разные компиляторы, я постараюсь убедиться, что его переносимость всячески иtypedef
- один из них.когда я начал программировать с помощью компилятора Turbo C на платформе Windows, он дал нам размер
int
2. Когда я перешел на платформу Linux и gcc complier, размер, который я получаю, равен 4. Если бы я разработал программу с использованием Turbo C, которая опиралась на утверждение, чтоsizeof( int )
всегда два, он не был бы правильно портирован на мою новую платформу.надеюсь, что это помогает.
следующая цитата из K&R не связано с вашим запросом, но я опубликовал его тоже ради завершения.
во-вторых-чтобы обеспечить лучшую документацию
второй целью определения типов должно обеспечить лучшую документации программы - тип с именем Treeptr может быть легче понять, чем одна объявлен только в качестве указатель на сложную структуру.
есть много причин на это. Что я думаю:
- Typename становится короче и, следовательно, код также меньше и более читаемым.
- эффект сглаживания для более длинных имен структуре.
- Конвенция используется в частности команда / компании / Стиль.
- портирование - имеют одинаковое имя во всех ОС и машине. Его собственная структура данных может немного отличаться.
большинство из этих шаблонов являются плохими практиками, которые происходят от чтения и копирования существующего плохого кода. Часто они отражают непонимание того, что C делает или не требует.
- сродни
#define BEGIN {
за исключением того, что он сохраняет некоторые набрав вместо того, чтобы делать больше.- сродни
#define FALSE 0
. Если ваша идея "байт" является наименьшей адресуемой единицей,char
байт по определению. Если ваша идея "байт" является октетом, то либоchar
тип октета, или ваша машина не имеет октетного типа.- это действительно уродливая стенография для людей, которые не могут коснуться типа...
- - это ошибка. Он должен быть!-Еще -4--> или лучше
uint32_t
следует просто использовать непосредственно.- это то же самое, что и 4. Заменить
uint32_t
Сint16_t
.пожалуйста, поставьте "считаются вредными" печать на них всех.
typedef
следует использовать, когда вам действительно нужно создать новый тип, определение которого может измениться в течение жизни цикл вашего кода или когда код переносится на другое оборудование, а не потому, что вы думаете, что C будет "красивее" с разными именами типов.
мы используем его, чтобы сделать его специфичным для проекта / платформы, все имеет общее соглашение об именах
pname_int32, pname_uint32, pname_uint8
-- pname-это имя проекта / платформы / модуляи некоторые директивы #define
pname_malloc, pname_strlen
он легче читается и сокращает длинные типы данных, такие как unsigned char для pname_uint8, также делая его соглашением во всех модулях.
при переносе нужно просто изменить один файл , что делает портирование легко.
чтобы сократить длинную историю короткой, возможно, вы захотите сделать это, чтобы сделать ваш код переносимым (с меньшими усилиями/редактированием). Таким образом, вы не зависите от 'int', вместо этого вы используете целое число, которое может быть все, что вы хотите.
все
[|u]intN_t
типы, где N=8/16/32/64 и так далее, определяются для каждой архитектуры таким точным образом. Это прямое следствие того, что стандарт не устанавливает, чтоchar
,int
,float
и т. д. имеет ровно n бит - это было бы безумием. Вместо этого стандарт определяет минимальные и максимальные значения каждого типа как гарантии программисту, и в различных архитектурах типы вполне могут превышать эти границы. Это не редкость.в
typedef
s в вашем посте используются для определенных типов определенной длины, в определенной архитектуре. Это, вероятно, не лучший выбор именования;u32
иs16
немного коротковаты, на мой взгляд. Кроме того, это своего рода плохая вещь, чтобы выставить именаulg
иuch
, можно было бы префикс их с конкретной строкой приложения, так как они, очевидно, не будут выставлены.надеюсь, что это помогает.