Почему программисты 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-разрядным целым числом без знака и использовать новый тип в коде. Когда вам нужно скомпилировать на другой реализации, вы просто изменитеtypedefs.
иногда он используется для уменьшения громоздкой вещи, как
volatile unsigned longк чему-то более компактному, напримерvuint32_t.в других случаях это помогает с переносимостью, так как типы, такие как
intне всегда одинаковы на каждой платформе. С помощью typedef вы можете установить класс хранения, который вас интересует, в ближайшее соответствие платформы без изменения всего исходного кода.
Ниже приводится цитата из языка программирования C (K&R)
помимо чисто эстетических вопросов, есть две основные причины для использования оператор typedef.
во-первых-для параметризации программы
во-первых, чтобы параметризовать программу против проблем переносимости. Если типов используются типы данных это может быть зависимым от машины, только у типов, нужно меняться, когда программа перемещается.
одной из распространенных ситуаций является использование typedef имен для различных целых количества, после этого делают соотвествующее набор вариантов short, int и long для каждой главной машины. типы, как типы size_t и ptrdiff_t из стандартной библиотеки примеры.
выделенные курсивом части говорят нам, что программисты
typedefосновной тип для переносимости. Если я хочу убедиться, что моя программа работает на разных платформах, используя разные компиляторы, я постараюсь убедиться, что его переносимость всячески иtypedef- один из них.когда я начал программировать с помощью компилятора Turbo C на платформе Windows, он дал нам размер
int2. Когда я перешел на платформу 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 бит - это было бы безумием. Вместо этого стандарт определяет минимальные и максимальные значения каждого типа как гарантии программисту, и в различных архитектурах типы вполне могут превышать эти границы. Это не редкость.в
typedefs в вашем посте используются для определенных типов определенной длины, в определенной архитектуре. Это, вероятно, не лучший выбор именования;u32иs16немного коротковаты, на мой взгляд. Кроме того, это своего рода плохая вещь, чтобы выставить именаulgиuch, можно было бы префикс их с конкретной строкой приложения, так как они, очевидно, не будут выставлены.надеюсь, что это помогает.