Typedef declaration
The keyword typedef is used in a declaration, in the grammatical position of a storage-class specifier, except that it does not affect storage or linkage:
typedef int int_t; // declares int_t to be an alias for the type int typedef char char_t, *char_p, (*fp)(void); // declares char_t to be an alias for char // char_p to be an alias for char* // fp to be an alias for char(*)(void)
Contents
[edit] Explanation
If a declaration uses typedef as storage-class specifier, every declarator in it defines an identifier as an alias to the type specified. Since only one storage-class specifier is permitted in a declaration, typedef declaration cannot be static or extern.
typedef declaration does not introduce a distinct type, it only establishes a synonym for an existing type, thus typedef names are compatible with the types they alias. Typedef names share the name space with ordinary identifiers such as enumerators, variables and function.
A typedef for a VLA can only appear at block scope. The length of the array is evaluated each time the flow of control passes over the typedef declaration, as opposed to the declaration of the array itself:
void copyt(int n) { typedef int B[n]; // B is a VLA, its size is n, evaluated now n += 1; B a; // size of a is n from before +=1 int b[n]; // a and b are different sizes for (int i = 1; i n; i++) a[i-1] = b[i]; }
[edit] Notes
typedef name may be an incomplete type, which may be completed as usual:
typedef int A[]; // A is int[] A a = {1, 2}, b = {3,4,5}; // type of a is int[2], type of b is int[3]
typedef declarations are often used to inject names from the tag name space into the ordinary name space:
typedef struct tnode tnode; // tnode in ordinary name space // is an alias to tnode in tag name space struct tnode { int count; tnode *left, *right; // same as struct tnode *left, *right; }; // now tnode is also a complete type tnode s, *sp; // same as struct tnode s, *sp;
They can even avoid using the tag name space at all:
typedef struct { double hi, lo; } range; range z, *zp;
Typedef names are also commonly used to simplify the syntax of complex declarations:
// array of 5 pointers to functions returning pointers to arrays of 3 ints int (*(*callbacks[5])(void))[3] // same with typedefs typedef int arr_t[3]; // arr_t is array of 3 int typedef arr_t* (*fp)(void); // pointer to function returning arr_t* fp callbacks[5];
Libraries often expose system-dependent or configuration-dependent types as typedef names, to present a consistent interface to the users or to other library components:
#if defined(_LP64) typedef int wchar_t; #else typedef long wchar_t; #endif
[edit] References
Объявления Typedef
Объявление typedef — это объявление с typedef в качестве класса хранения. Декларатор становится новым типом. Объявления typedef можно использовать для создания более коротких или более понятных имен для типов, уже определенных в C, или для объявленных типов. Имена typedef позволяют инкапсулировать детали реализации, которые могут измениться.
Объявление typedef интерпретируется точно так же, как и объявление переменной или функции, но идентификатор становится синонимом типа, а не принимает тип, указанный в объявлении.
Синтаксис
declaration :
declaration-specifiers init-declarator-list необ. ;
declaration-specifiers :
storage-class-specifier declaration-specifiers необ.
type-specifier declaration-specifiers необ.
type-qualifier declaration-specifiers необ.
storage-class-specifier :
typedef
type-specifier :
void
char
short
int
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name
Объявление typedef не создает новые типы. Оно создает синонимы для существующих типов или имена для типов, которые могут определяться другими способами. Если имя typedef используется как спецификатор типа, его можно использовать в сочетании с определенными спецификаторами типа (но нельзя использовать с другими спецификаторами). К допустимым модификаторам относятся const и volatile .
Имена typedef используют то же пространство имен, что и обычные идентификаторы. (Дополнительные сведения см. в разделе Пространства имен.) Таким образом, программа может иметь имя typedef и идентификатор локального область с тем же именем. Пример:
typedef char FlagType; int main() < >int myproc( int )
При объявлении идентификатора локального область с тем же именем, что и определение типа, или при объявлении члена структуры или объединения в том же область или во внутренней область, необходимо также указать описатель типа. Следующий пример иллюстрирует это ограничение:
typedef char FlagType; const FlagType x;
Чтобы повторно использовать имя FlagType для идентификатора, члена структуры или члена объединения, необходимо указать тип:
const int FlagType; /* Type specifier required */
const FlagType; /* Incomplete specification */
поскольку FlagType воспринимается как часть типа, а не как заново объявляемый идентификатор. Это объявление недопустимо, как и
С помощью typedef можно объявить любой тип, включая типы указателя, функции и массива. Имя typedef для типа указателя на структуру или объединение можно объявить до определения типа структуры или объединения, если только определение находится в той же области видимости, что и объявление.
Имена typedef можно использовать, чтобы сделать код более понятным. Все три следующих объявления signal задают один и тот же тип, причем в первом объявлении имена typedef не используются.
typedef void fv( int ), (*pfv)( int ); /* typedef declarations */ void ( *signal( int, void (*) (int)) ) ( int ); fv *signal( int, fv * ); /* Uses typedef type */ pfv signal( int, pfv ); /* Uses typedef type */
Примеры
В следующих примерах показаны объявления typedef:
typedef int WHOLE; /* Declares WHOLE to be a synonym for int */
Например, теперь можно использовать в объявлении переменной, WHOLE такой как WHOLE i; или const WHOLE i; . Однако объявление long WHOLE i; недопустимо.
typedef struct club < char name[30]; int size, year; >GROUP;
Этот оператор объявляет имя GROUP как тип структуры с тремя членами. Поскольку также указан тег структуры, club , в объявлениях можно использовать как имя typedef ( GROUP ), так и тег структуры. Необходимо использовать struct ключевое слово с тегом , а ключевое слово нельзя использовать struct с именем определения типа.
typedef GROUP *PG; /* Uses the previous typedef name to declare a pointer */
Тип PG объявлен как указатель на тип GROUP , который, в свою очередь, определен как тип структуры.
typedef void DRAWF( int, int );
В этом примере задан тип DRAWF для функции, не возвращающей никакого значения и принимающей два аргумента int. Это означает, например, что объявление
typedef specifier
The typedef specifier, when used in a declaration, specifies that the declaration is a typedef declaration rather than a variable or function declaration. Typically, the typedef specifier appears at the start of the declaration, though it is permitted to appear after the type specifiers, or between two type specifiers.
A typedef declaration may declare one or many identifiers on the same line (e.g. int and a pointer to int), it may declare array and function types, pointers and references, class types, etc. Every identifier introduced in this declaration becomes a typedef-name, which is a synonym for the type of the object or function that it would become if the keyword typedef were removed.
The typedef specifier cannot be combined with any other specifier except for type-specifiers.
The typedef-names are aliases for existing types, and are not declarations of new types. Typedef cannot be used to change the meaning of an existing type name (including a typedef-name). Once declared, a typedef-name may only be redeclared to refer to the same type again. Typedef names are only in effect in the scope where they are visible: different functions or class declarations may define identically-named types with different meaning.
The typedef specifier may not appear in the declaration of a function parameter nor in the decl-specifier-seq of a function definition:
void f1(typedef int param); // ill-formed typedef int f2() {} // ill-formed
The typedef specifier may not appear in a declaration that does not contain a declarator:
typedef struct X {}; // ill-formed
[edit] typedef-name for linkage purposes
Formally, if the typedef declaration defines an unnamed class or enum, the first typedef-name declared by the declaration to be that class type or enum type is used to denote the class type or enum type for linkage purposes only. For example, in typedef struct { /* . */ } S ; , S is a typedef-name for linkage purposes. The class or enum type defined in this way has external linkage (unless it’s in an unnamed namespace).
An unnamed class defined in this way should only contain C-compatible constructs. In particular, it must not
- declare any members other than non-static data members, member enumerations, or member classes,
- have any base classes or default member initializers, or
- contain a lambda-expression,
and all member classes must also satisfy these requirements (recursively).
[edit] Keywords
[edit] Notes
type aliases provide the same functionality as typedefs using a different syntax, and are also applicable to template names.
[edit] Example
// simple typedef typedef unsigned long ulong; // the following two objects have the same type unsigned long l1; ulong l2; // more complicated typedef typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10]; // the following two objects have the same type int a1[10]; arr_t a2; // beware: the following two objects do not have the same type const intp_t p1 = 0; // int *const p1 = 0 const int *p2; // common C idiom to avoid having to write "struct S" typedef struct {int a; int b;} S, *pS; // the following two objects have the same type pS ps1; S* ps2; // error: storage-class-specifier cannot appear in a typedef declaration // typedef static unsigned int uint; // typedef can be used anywhere in the decl-specifier-seq long unsigned typedef int long ullong; // more conventionally spelled "typedef unsigned long long int ullong;" // std::add_const, like many other metafunctions, use member typedefs templateclass T> struct add_const { typedef const T type; }; typedef struct Node { struct listNode* next; // declares a new (incomplete) struct type named listNode } listNode; // error: conflicts with the previously declared struct name // C++20 error: "struct with typedef name for linkage" has member functions typedef struct { void f() {} } C_Incompatible;
[edit] Defect Reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 576 | C++98 | typedef was not allowed in the entire function definition | allowed in function body |
CWG 2071 | C++98 | typedef could appear in a declaration that does not contain a declarator | now disallowed |