Перейти к содержимому

Typedef c что это

  • автор:

Псевдонимы и определения типов (C++)

Объявление псевдонима можно использовать для объявления имени, используемого в качестве синонима для ранее объявленного типа. (Этот механизм также называется неформальным псевдонимом типа. Этот механизм также можно использовать для создания шаблона псевдонима, который может быть полезен для пользовательских распределителей.

Синтаксис

using identifier = type; 

Замечания

идентификатор
Имя псевдонима.

type
Идентификатор типа, для который вы создаете псевдоним.

Псевдоним не вводит новый тип и не может изменить значение существующего имени типа.

Простейшая форма псевдонима эквивалентна механизму typedef C++03:

// C++11 using counter = long; // C++03 equivalent: // typedef long counter; 

Обе эти формы позволяют создавать переменные типа counter . Псевдоним типа для std::ios_base::fmtflags , приведенный в следующем примере, может быть более полезен.

// C++11 using fmtfl = std::ios_base::fmtflags; // C++03 equivalent: // typedef std::ios_base::fmtflags fmtfl; fmtfl fl_orig = std::cout.flags(); fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase | std::cout.hex; // . std::cout.flags(fl_hex); 

Псевдонимы также работают с указателями функций, но гораздо более удобочитаемыми, чем эквивалентный типдф:

// C++11 using func = void(*)(int); // C++03 equivalent: // typedef void (*func)(int); // func can be assigned to a function pointer value void actual_function(int arg) < /* some code */ >func fptr = &actual_function; 

Ограничение typedef механизма заключается в том, что он не работает с шаблонами. Напротив, синтаксис псевдонима типа в C ++11 позволяет создавать шаблоны псевдонимов:

template using ptr = T*; // the name 'ptr' is now an alias for pointer to T ptr ptr_int; 

Пример

В следующем примере показано, как использовать шаблон псевдонима с пользовательским механизмом выделения памяти — в данном случае целочисленным векторным типом. Можно заменить любой тип int , чтобы создать удобный псевдоним, чтобы скрыть сложные списки параметров в основном функциональном коде. Используя пользовательский распределитель во всем коде, вы можете улучшить удобочитаемость и снизить риск возникновения ошибок, вызванных опечатками.

#include #include template struct MyAlloc < typedef T value_type; MyAlloc() < >template MyAlloc(const MyAlloc&) < >bool operator==(const MyAlloc&) const < return true; >bool operator!=(const MyAlloc&) const < return false; >T * allocate(const size_t n) const < if (n == 0) < return nullptr; >if (n > static_cast(-1) / sizeof(T)) < throw std::bad_array_new_length(); >void * const pv = malloc(n * sizeof(T)); if (!pv) < throw std::bad_alloc(); >return static_cast(pv); > void deallocate(T * const p, size_t) const < free(p); >>; #include using MyIntVector = std::vector>; #include int main () < MyIntVector foov = < 1701, 1764, 1664 >; for (auto a: foov) std::cout
1701 1764 1664 

Определения типов

Объявление typedef вводит имя, которое в область становится синонимом типа, заданного частью объявления типа.

Объявления typedef можно использовать для создания более коротких или более значимых имен для типов, уже определенных языком или типами, объявленными вами. Имена typedef позволяют инкапсулировать детали реализации, которые могут измениться.

В отличие от объявлений class struct и union enum объявлений, объявления typedef не вводят новые типы; они вводят новые имена для существующих типов.

Имена, объявленные с использованием typedef того же пространства имен, что и другие идентификаторы (кроме меток инструкций). Поэтому они не могут использовать тот же идентификатор, что и ранее объявленное имя, за исключением объявления типа класса. Рассмотрим следующий пример:

// typedef_names1.cpp // C2377 expected typedef unsigned long UL; // Declare a typedef name, UL. int UL; // C2377: redefined. 

Правила скрытия имен, относящиеся к другим идентификаторам, также управляют видимостью имен, объявленных с помощью typedef . Поэтому следующий код допустим в C++:

// typedef_names2.cpp typedef unsigned long UL; // Declare a typedef name, UL int main() < unsigned int UL; // Redeclaration hides typedef name >// typedef UL back in scope 

Другой экземпляр имени скрыт:

// typedef_specifier1.cpp typedef char FlagType; int main() < >void myproc( int )

При объявлении идентификатора локального область с таким же именем, как и typedef при объявлении члена структуры или объединения в том же область или во внутреннем область, необходимо указать описатель типа. Например:

typedef char FlagType; const FlagType x; 

Чтобы повторно использовать имя FlagType для идентификатора, члена структуры или члена объединения, необходимо указать тип:

const int FlagType; // Type specifier required 
const FlagType; // Incomplete specification 

так как принимается FlagType как часть типа, а не идентификатор, который выполняется повторно. Это объявление принимается как незаконное объявление, аналогичное следующему:

int; // Illegal declaration 

Можно объявить любой тип с typedef помощью указателя, функции и типов массивов. Имя typedef для типа указателя на структуру или объединение можно объявить до определения типа структуры или объединения, если только определение находится в той же области видимости, что и объявление.

Примеры

Одним из способов использования объявлений является создание объявлений typedef более единообразным и компактным. Например:

typedef char CHAR; // Character type. typedef CHAR * PSTR; // Pointer to a string (char *). PSTR strchr( PSTR source, CHAR target ); typedef unsigned long ulong; ulong ul; // Equivalent to "unsigned long ul;" 

typedef Чтобы указать основные и производные типы в одном объявлении, можно разделить деклараторы с запятыми. Например:

typedef char CHAR, *PSTR; 

В следующем примере задан тип DRAWF для функции, не возвращающей никакого значения и принимающей два аргумента int.

typedef void DRAWF( int, int ); 

После приведенной выше typedef инструкции объявление

DRAWF box; 

будет эквивалентно следующему:

void box( int, int ); 

typedef часто объединяется с struct объявлением и именем определяемых пользователем типов:

// typedef_specifier2.cpp #include typedef struct mystructtag < int i; double f; >mystruct; int main()
10 0.990000 

Повторная отмена типов

Объявление typedef можно использовать для повторного объявления того же имени, чтобы ссылаться на тот же тип. Например:

Исходный файл file1.h :

// file1.h typedef char CHAR; 

Исходный файл file2.h :

// file2.h typedef char CHAR; 

Исходный файл prog.cpp :

// prog.cpp #include "file1.h" #include "file2.h" // OK 

prog.cpp Файл содержит два файла заголовка, оба из которых содержат typedef объявления для имени CHAR . Если в обеих объявлениях указывается один и тот же тип, такое повторное объявление допустимо.

Не typedef удается переопределить имя, которое ранее было объявлено в качестве другого типа. Рассмотрим эту альтернативу file2.h :

// file2.h typedef int CHAR; // Error 

Компилятор выдает ошибку из-за prog.cpp попытки повторного объявления имени CHAR для ссылки на другой тип. Эта политика распространяется на такие конструкции, как:

typedef char CHAR; typedef CHAR CHAR; // OK: redeclared as same type typedef union REGS // OK: name REGS redeclared < // by typedef name with the struct wordregs x; // same meaning. struct byteregs h; >REGS; 

typedefs в C++ и C

typedef Использование описателя с типами классов поддерживается в основном из-за практики ANSI C объявления неименованных структур в typedef объявлениях. Например, многие программисты C используют следующую идиому:

// typedef_with_class_types1.cpp // compile with: /c typedef struct < // Declare an unnamed structure and give it the // typedef name POINT. unsigned x; unsigned y; >POINT; 

Преимущество такого объявления заключает в том, что можно выполнять объявления

POINT ptOrigin; 
struct point_t ptOrigin; 

В C++разница между typedef именами и реальными типами (объявленными с class помощью , struct union и enum ключевое слово) более различается. Хотя практика объявления безымяной структуры в typedef инструкции по-прежнему работает, она не предоставляет нотационных преимуществ, как это делает в C.

// typedef_with_class_types2.cpp // compile with: /c /W1 typedef struct < int POINT(); unsigned x; unsigned y; >POINT; 

В предыдущем примере объявляется класс с именем с использованием синтаксиса неназванного POINT класса typedef . POINT считается именем класса, однако к именам, предоставленным таким образом, применяются следующие ограничения.

  • Имя (синоним) не может отображаться после classstruct префикса или union префикса.
  • Имя нельзя использовать в качестве конструктора или деструктора в объявлении класса.

В итоге этот синтаксис не предоставляет никакого механизма для наследования, построения или уничтожения.

Что такое typedef в C++?

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

// Исходный тип данных typedef double Distance; // Использование псевдонима Distance distanceValue = 10.5;

Преимущества использования typedef:

  1. Улучшение читаемости кода: Создание псевдонимов позволяет использовать более понятные имена для сложных типов данных.
  2. Повышение поддерживаемости: Использование typedef упрощает изменение типов данных в будущем, поскольку изменения нужно вносить только в одном месте кода.
  3. Сокращение кода: Псевдонимы уменьшают количество повторяющегося кода, особенно при работе с длинными типами или структурами.

Typedef c что это

Что такое typedef, и чем он отличается от #define?

Часть 2. Для чего еще нужен typedef.

Итак, в первой части мы уже определились с тем, что такое typedef и чем он так похож и не похож на #define.

typedef вводит новое имя (синоним) для существующего типа. Но только этим все не ограничивается Чего такого еще может typedef, чего невозможно сделать с #define?

С помощью typedef может быть объявлен любой тип, включая типы функции или массива.

typedef double (* MATH)(); // MATH — новое имя типа, представляющее указатель на
//функцию, возвращающую значения типа double
MATH cos; // cos — это указатель на функцию, возвращающую значения типа double

Можно привести эквивалентное объявление — double (* cos)();

typedef char SIMB[40]; //SIMB — массив из сорока символов
SIMB person; //переменная person — тоже массив из сорока символов

Это эквивалентно объявлению — char person[40];

Помимо этого, имена типов могут использоваться еще и в списке формальных параметров (в объявлении функций), в операциях приведения типов и в операции sizeof.

typedef способен весьма облегчить нам жизнь. И не только нам.

typedef можно использовать, чтобы значительно упростить синтаксис сложных объявлений (воззаботимся же, братия, о тех бедных программистах, которые приИдут после нас). Используя typedef, можно сделать простым даже объявление стандартной функции set_new_handler:

typedef void (*new_handler)();
new_handler set_new_handler(new_handler);

Итак, new_handler — указатель на функцию, которая не имеет параметров и ничего не возвращает, и set_new_handler — функция, которая берет new_handler как параметр и возвращает в результате new_handler. Все выглядит очень просто. Если сделать это без typedef, тому, кто будет сопровождать потом этот код, будет лучше сразу застрелиться.

void (*set_new_handler(void (*)()))();

Это, по сути, то же самое. Но зато выглядит ужасно.

Давайте рассмотрим класс, используемый для осуществления связи по протоколу IP. Это может быть что-то, похожее на такое определение сокета:

typedef int AddressFamily;
typedef int SocketType;
typedef int Protocol;

class Socket
public:
Socket(AddressFamily family, SocketType type, Protocol protocol);
. . .

Мы видим определение трех typedef — AddressFamily, SocketType, и Protocol. Они идентифицируют три определяющие характеристики, необходимые для создания сокета связи (смотрим книги Стивенса по TCP/IP — пригодится). В этом контексте typedef использовался, чтобы определить три различных логических типа, хотя все они, в этом случае, один и тот же фактический тип — int. Такое использование typedef иногда называют «концептуальное определение типов».

Таким образом, конструктор Socket явно более понятен, чем если бы эти три параметра были бы определены просто, как int. Одно из преимуществ концептуального определения типов состоит в том, что они обеспечивают логически более понятное и простое определение классов.

Другое преимущество концептуального определения типов в том, что оно обеспечивает некоторую независимость от платформы. Посмотрим на стандартные типы size_t и ptrdiff_t, которые обычно определяются так:

typedef unsigned int size_t;
typedef int ptrdiff_t;

Когда тип ptrdiff_t встречается в коде, сразу становится понятно, что кое-кто здесь собирается оценить разницу между указателями. Если же тип был бы просто int, скорее всего сначала подумалось бы об арифметике или операциях индексации, которые более обычны для простого int. Точно так же и size_t склоняет думать о размерности (количестве байтов), а не о некой произвольной целочисленной мере. Однако, это еще не все. int (или unsigned int) могут и не быть типом, соответствующим для представления этих величин на данной платформе (ну, не хватит их размерности). В конкретной реализации эти типы могут быть переопределены, чтобы они соответствовали поддерживаемым (реализацией) платформам. И тогда не будет никакой необходимости менять что-либо в пользовательском коде — независимость.

Одной из возможных ошибок, связанных с применением typedef, может стать ошибка с перегрузкой функций. Напомним, что сигнатуры перегруженных функций должны отличаться, как минимум, типом параметра или количеством параметров. Но списки параметров могут быть одинаковыми, несмотря на то, что выглядят абсолютно разными.

struct Phone <. >;
struct Record <. >;

typedef Phone Tel_no;

Record lookup(const Phone&);
Record lookup(const Telno&); // Telno и Phone это тот же самый тип

Выглядит, как вполне разные типы. А на самом деле — одно и тоже, ведь Telno — не новый тип, а всего лишь синоним типа Phone.

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

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

Если у вас возникает потребность подробного рассмотрения какого-либо вопроса по С++, пишите нам, мы попытаемся вам помочь.

Сергей Малышев (aka Михалыч).

Зачем нужен typedef?

typedef используется для создания псевдонимов других типов данных. Приведенный пример лучше скорректировать, например:

typedef struct LINE < . >t_line; 

typedef может использоваться не только для структур, но и для любых других типов:

typedef int t_message_id; typedef enum e_Colour t_colour; 

Основные причины использования typedef -объявлений

Сокращение имен типов данных для улучшения читабельности и простоты набора кода. В приведенном примере без использования typedef придется писать struct LINE . В C++ эта проблема решена (можно просто писать LINE ), однако могут использоваться длинные названия типов, например: std::vector::size_type может быть сокращено с помощью typedef . t_lvecsz .

Абстрагирование от используемого в данной реализации типа данных для облегчения возможных изменений реализации. Например, struct LINE может быть объявлено так:

struct LINE < float x1,y1,x2,y2; >; 

и во всем остальном коде для представления координат использоваться тип float . При возникновении необходимости перехода, например, к типу double потребуется вносить множество изменений в код (и, как всегда, где-то забыть внести изменения). Эта проблема хорошо решается с помощью следующих объявлений:

typedef float t_coord; struct LINE < t_coord x1,y1,x2,y2; >; 

Также typedef может использоваться для облегчения создания объявлений сложных типов (что-то вроде «массив указателей на функции, возвращающие указатель на структуру и т.д.»).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *