Typedef - Typedef
typedef это зарезервированное ключевое слово в языки программирования C и C ++. Используется для создания дополнительного имени (псевдоним) для другого тип данных, но не создает новый тип[1], за исключением непонятного случая с квалифицированный typedef типа массива, где квалификаторы typedef передаются в тип элемента массива[2]. Таким образом, он часто используется для упрощения синтаксиса объявления сложных структуры данных состоящий из структура и типы профсоюзов, но столь же распространен в предоставлении конкретных описательных имен типов для целочисленные типы данных разной длины.
Синтаксис
Синтаксис объявления typedef:[3]
typedef
объявление типа;
Имя нового псевдонима типа следует тому же синтаксису, что и объявление любого другого идентификатора C, поэтому в более подробной форме:
typedef
определение типа идентификатор
в Стандартная библиотека C И в POSIX спецификации идентификатор для определения typedef часто дополняется суффиксом _t
, например, в size_t и time_t. Это практикуется в других системах кодирования, хотя POSIX явно резервирует эту практику для POSIX типы данных.
Примеры
typedef int длина;
Это создает тип длина
как синоним типа int
.
Использование документации
Объявление typedef может использоваться в качестве документации, указывая значение переменной в контексте программирования, например, оно может включать выражение единицы измерения или количества. Общие объявления,
int текущая скорость;int рекорд;пустота поздравлять(int твой счет) { если (твой счет > рекорд) { // ... }}
может быть выражено объявлением специфичных для контекста типов:
typedef int км_пер_час;typedef int точки;// `km_per_hour` здесь является синонимом` int`, и поэтому компилятор обрабатывает// наши новые переменные как целые числа.км_пер_час текущая скорость;точки рекорд;пустота поздравлять(точки твой счет) { если (твой счет > рекорд) { // ... }}
Оба раздела кода выполняются идентично. Однако использование объявлений typedef во втором блоке кода дает понять, что две переменные, представляющие один и тот же тип данных int
, хранить разные или несовместимые данные. Определение в поздравлять()
из твой счет
указывает программисту, что текущая скорость
(или любая другая переменная, не объявленная как точки
) не следует передавать в качестве аргумента. Это было бы не так очевидно, если бы оба были объявлены как переменные int
тип данных. Однако указание только для программиста; компилятор C / C ++ считает, что обе переменные имеют тип int
и не помечает предупреждения о несоответствии типов или ошибки для "неправильных" типов аргументов для поздравляю (баллы your_score)
во фрагменте кода ниже:
пустота фу() { км_пер_час км100 = 100; поздравлять(км100);}
Упрощение типов
Typedef может использоваться для упрощения объявления составного типа (структура, союз ) или указатель тип.[4] Например,
структура MyStruct { int data1; char данные2;};
Это определяет тип данных struct MyStruct
. Для объявления переменной этого типа в C также требуется ключевое слово структура
, но его можно опустить в C ++:
struct MyStruct a;
Объявление typedef устраняет необходимость указывать структура
в C. Например, объявление
typedef struct MyStruct newtype;
сводится к:
newtype a;
Объявление структуры и typedef также можно объединить в один оператор:
typedef структура MyStruct { int data1; char данные2;} Новый тип;
Или это можно использовать следующим образом:
typedef структура { int data1; char данные2;} Новый тип;
В C ++, в отличие от C, ключевые слова структура
, класс
, и перечислить
являются необязательными в объявлениях переменных, которые отделены от определений, если нет двусмысленности с другим идентификатором:
структура MyStruct Икс;MyStruct у;
Как таковой, MyStruct
можно использовать везде Новый тип
может быть использован. Однако обратное неверно; например, методы конструктора для MyStruct
нельзя назвать Новый тип
.
Печально известный пример, когда даже C ++ нуждается в структура
ключевое слово - это POSIX системный вызов stat который использует в своих аргументах структуру с таким же именем:
int стат(const char *имя файла, структура стат *бух){ // ...}
Здесь оба C а также C ++ нужен структура
ключевое слово в определении параметра.
Указатели
Typedef может использоваться для определения нового типа указателя.
typedef int *intptr;intptr ptr;// Такой же как:// int * ptr;
intptr
это новый псевдоним с типом указателя int *
. Определение, intptr ptr;
, определяет переменную ptr
с типом int *
. Так, ptr
это указатель, который может указывать на переменную типа int
.
Использование typedef для определения нового типа указателя иногда может привести к путанице. Например:
typedef int *intptr;// Оба 'cliff' и 'allen' имеют тип int *.intptr Утес, аллен;// 'cliff2' имеет тип int *, а 'allen2' имеет тип int **.intptr cliff2, *allen2;// Такой же как:// intptr cliff2;// intptr * allen2;
Над, intptr cliff, allen;
означает определение 2 переменных с помощью int *
типа для обоих. Это потому, что тип, определенный typedef, является типом, а не расширением. Другими словами, intptr
, какой int *
тип, украшает оба Утес
и аллен
. За intptr cliff2, * allen2;
, то intptr
шрифт украшает cliff2
и * allen2
. Так, intptr cliff2, * allen2;
эквивалентно двум отдельным определениям, intptr cliff2;
и intptr * allen2
. intptr * allen2
Значит это allen2
это указатель, указывающий на память с int *
тип. Вскоре allen2
имеет тип, int **
.
Структуры и указатели структур
Typedefs также может упростить определения или объявления для структура указатель типы. Учти это:
структура Узел { int данные; структура Узел *nextptr;};
Используя typedef, приведенный выше код можно переписать следующим образом:
typedef структура Узел Узел;структура Узел { int данные; Узел *nextptr;};
В C можно объявить несколько переменных одного и того же типа в одном операторе, даже смешивая структуру с указателем или не указателями. Однако, чтобы обозначить ее как указатель, нужно поставить перед каждой переменной звездочку. Далее программист может предположить, что errptr
действительно был Узел *
, но опечатка означает, что errptr
это Узел
. Это может привести к незначительным синтаксическим ошибкам.
структура Узел *startptr, *endptr, *Curptr, *prevptr, errptr, *refptr;
Определив typedef Узел *
, гарантируется, что все переменные являются типами указателей на структуру, или, скажем, каждая переменная является тип указателя указывая на тип конструкции.
typedef структура Узел* NodePtr;NodePtr startptr, endptr, Curptr, prevptr, errptr, refptr;
Указатели функций
int do_math(плавать arg1, int arg2) { вернуть arg2;}int call_a_func(int (*call_this)(плавать, int)) { int вывод = call_this(5.5, 7); вернуть вывод;}int конечный результат = call_a_func(&do_math);
Предыдущий код можно переписать со спецификациями typedef:
typedef int (*MathFunc)(плавать, int);int do_math(плавать arg1, int arg2) { вернуть arg2;}int call_a_func(MathFunc call_this) { int вывод = call_this(5.5, 7); вернуть вывод;}int конечный результат = call_a_func(&do_math);
Вот, MathFunc
это новый псевдоним типа. А MathFunc
- указатель на функцию, которая возвращает целое число и принимает в качестве аргументов число с плавающей запятой, за которым следует целое число.
Когда функция возвращает указатель на функцию, без typedef это может быть еще более запутанным. Ниже приведен прототип функции сигнал (3) из FreeBSD:
пустота (*сигнал(int сиг, пустота (*func)(int)))(int);
Объявление функции выше является загадочным, поскольку оно не ясно показывает, что функция принимает в качестве аргументов или тип, который она возвращает. Начинающий программист может даже предположить, что функция принимает один int
в качестве аргумента и ничего не возвращает, но на самом деле ему также нужен указатель на функцию и он возвращает другой указатель на функцию. Более чисто можно написать:
typedef пустота (*sighandler_t)(int);sighandler_t сигнал(int сиг, sighandler_t func);
Массивы
Typedef также можно использовать для упрощения определения типов массивов. Например,
typedef char arrType[6];arrType обр = {1, 2, 3, 4, 5, 6};arrType *pArr;// Такой же как:// char arr [6] = {1, 2, 3, 4, 5, 6};// char (* pArr) [6];
Вот, arrType
это новый псевдоним для символ [6]
type, который является типом массива с 6 элементами. За arrType * pArr;
, pArr
указатель, указывающий на память символ [6]
тип.
Приведение типов
Typedef создается с использованием типа определение синтаксис, но может использоваться, как если бы он был создан с использованием типа В ролях синтаксис. (Приведение типов изменяет тип данных.) Например, в каждой строке после первой строки:
// `funcptr` - это указатель на функцию, которая принимает` double` и возвращает `int`.typedef int (*funcptr)(двойной);// Допустимо для C или C ++.funcptr Икс = (funcptr) НОЛЬ;// Допустимо только в C ++.funcptr у = funcptr(НОЛЬ);funcptr z = static_cast<funcptr>(НОЛЬ);
funcptr
используется в левой части для объявления переменной и используется в правой части для приведения значения. Таким образом, typedef может использоваться программистами, которые не хотят выяснять, как преобразовать синтаксис определения в синтаксис приведения типов.
Без typedef, как правило, невозможно взаимозаменяемо использовать синтаксис определения и синтаксис приведения. Например:
пустота *п = НОЛЬ;// Это допустимо.int (*Икс)(двойной) = (int (*)(двойной)) п;// Левая часть недопустима.int (*)(двойной) у = (int (*)(двойной)) п;// Правая часть недопустима.int (*z)(двойной) = (int (*п)(двойной));
Использование в C ++
В C ++ имена типов могут быть сложными, а typedef предоставляет механизм для присвоения типу простого имени.
стандартное::вектор<стандартное::пара<стандартное::нить, int>> значения;за (стандартное::вектор<стандартное::пара<стандартное::нить, int>>::const_iterator я = значения.начинать(); я != значения.конец(); ++я){ стандартное::пара<стандартное::нить, int> const & т = *я; // ...}
и
typedef стандартное::пара<стандартное::нить, int> value_t;typedef стандартное::вектор<value_t> values_t;values_t значения;за (values_t::const_iterator я = значения.начинать(); я != значения.конец(); ++я){ value_t const & т = *я; // ...}
C ++ 11 представила возможность выражать typedefs с помощью с помощью
вместо того typedef
. Например, два вышеупомянутых typedef могут быть эквивалентно записаны как
с помощью value_t = стандартное::пара<стандартное::нить, int>;с помощью values_t = стандартное::вектор<value_t>;
Использовать с шаблонами
C ++ 03 не предоставляет шаблонный typedefs. Например, чтобы иметь строковая пара
представлять std :: pair
для каждого типа Т
один не можешь использовать:
шаблон<typename Т>typedef стандартное::пара<стандартное::нить, Т> струнная пара<Т>; // Не работает
Однако, если кто-то готов принять Stringpair
вместо строковая пара
, то можно достичь желаемого результата с помощью typedef внутри неиспользуемого в противном случае шаблонного класса или структуры:
шаблон<typename Т>класс струнная пара{частный: // Предотвратить создание экземпляра `stringpair `. струнная пара();общественный: // Делаем `stringpair :: type` представителем` std :: pair `. typedef стандартное::пара<стандартное::нить, Т> тип;};// Объявить переменную типа `std :: pair `. струнная пара<int>::тип my_pair_of_string_and_int;
В C ++ 11, шаблонные определения типов добавляются со следующим синтаксисом, который требует с помощью
ключевое слово, а не typedef
ключевое слово. (Видеть псевдонимы шаблонов.)[5]
шаблон <typename Т>с помощью струнная пара = стандартное::пара<стандартное::нить, Т>;// Объявить переменную типа `std :: pair `. струнная пара<int> my_pair_of_string_and_int;
Другие языки
В SystemVerilog, typedef ведет себя точно так же, как в C и C ++.[6]
Во многих статически типизированных функциональных языках, например Haskell, Миранда, OCaml и т. д. можно определить синонимы типа, которые аналогичны определениям типов в C. Пример в Haskell:
тип PairOfInts = (Int, Int)
В этом примере определен синоним типа PairOfInts
как целочисленный тип.
В Семя7 определение постоянного типа используется для введения синонима типа:
Тип const: myVector - целочисленный массив;
В Быстрый, используется typealias
ключевое слово для создания typedef:
typealias PairOfInts = (Инт, Инт)
C # содержит функцию, похожую на typedef или с помощью
синтаксис C ++.[7][5]
с помощью Новый тип = Глобальный::Система.Время выполнения.Взаимодействие.Маршал;с помощью otherType = Перечисления.MyEnumType;с помощью StringListMap = Система.Коллекции.Универсальный.Словарь<нить, Система.Коллекции.Универсальный.Список<нить>>;
В D ключевое слово псевдоним
[8] позволяет создавать синонимы типа или частичного типа.
структура Фу(Т){}псевдоним FooInt = Фу!int;псевдоним Весело = int делегировать(int);
Проблемы использования
Керниган и Ричи указали две причины использования typedef.[1] Во-первых, он предоставляет средства, позволяющие сделать программу более переносимой или более простой в обслуживании. Вместо того чтобы изменять тип при каждом появлении в исходных файлах программы, нужно изменить только один оператор typedef. size_t и ptrdiff_t в
Некоторые программисты выступают против широкого использования определений типов. Большинство аргументов основано на идее, что typedef просто скрывает фактический тип данных переменной. Например, Грег Кроа-Хартман, а Ядро Linux хакер и разработчик документации не рекомендует использовать их для чего-либо, кроме объявления прототипов функций. Он утверждает, что такая практика не только излишне запутывает код, но также может привести к тому, что программисты будут случайно неправильно использовать большие структуры, считая их простыми типами.[9]
Смотрите также
Рекомендации
- ^ а б Керниган, Брейн В.; Ричи, Деннис М. (1988). Язык программирования C (2-е изд.). Энглвуд Клиффс, Нью-Джерси: Prentice Hall. п.147. ISBN 0-13-110362-8. Получено 18 июн 2016.
C предоставляет средство typedef для создания имен новых типов данных. … Следует подчеркнуть, что объявление typedef ни в каком смысле не создает новый тип; он просто добавляет новое имя для некоторого существующего типа.
- ^ "квалификатор константного типа". cppreference.com. Получено 2020-10-20.
- ^ "спецификатор typedef". cppreference.com. Получено 18 июн 2016.
- ^ Deitel, Paul J .; Дейтель, Х. М. (2007). C как программировать (5-е изд.). Верхняя Сэдл-Ривер, Нью-Джерси: Pearson Prentice Hall. ISBN 9780132404167. Получено 12 сентября 2012.
Имена структурных типов часто определяются с помощью typedef для создания более коротких имен типов.
- ^ а б "Введите псевдоним, шаблон псевдонима (начиная с C ++ 11) - cppreference.com". en.cppreference.com. Получено 2018-09-25.
- ^ Тала, Дипак Кумар. «Типы данных SystemVerilog, часть V». www.asic-world.com. ASIC Мир. Получено 25 сентября 2018.
- ^ http://msdn.microsoft.com/en-us/library/aa664765(VS.71).aspx
- ^ "Объявления - язык программирования D". dlang.org. Получено 2017-05-28.
- ^ Кроа-Хартман, Грег (2002-07-01). «Правильный стиль программирования ядра Linux». Linux журнал. Получено 2007-09-23.
Использование typedef скрывает только реальный тип переменной.