The typedef specifier is used to define a name that can be used as a synonym for
a type or derived type. You cannot use the typedef specifier inside a function
definition.
typedef-name:
identifier
A typedef declaration introduces a name that, within its scope, becomes a synonym for the type given by the decl-specifiers portion of the declaration. In contrast to the class, struct, union, and enum declarations, typedef declarations do not introduce new types—they introduce new names for existing types.
One use of typedef declarations is to make declarations more uniform and compact. For example:
typedef char CHAR; // Character type.
typedef CHAR * PSTR; // Pointer to a string (char *).
typedef CHAR __far * LPSTR // Far pointer to a string.
typedef CHAR __near * NPSTR // Near pointer to a string.
...
LPSTR _fstrchr( LPSTR source, CHAR target );
The names introduced by the above declarations are synonyms for the following types:
Name | Synonymous Type |
CHAR | char |
PSTR | char * |
LPSTR | char __far * |
NPSTR | char __near * |
The preceding example code declares a type name, CHAR. The CHAR type name is then used to define these derived type names: PSTR (a pointer to a string), LPSTR (a far pointer to a string), and NPSTR (a near pointer to a string). Finally, the names are used in declaring the function _fstrchr. To see how the typedefs can clarify declarations, contrast the above declaration of _fstrchr with the following declaration:
char __far * _fstrchr( char __far * source, char target );
To use typedef to specify fundamental and derived types in the same declaration, you can separate declarators with commas. For example:
typedef char CHAR, *PSTR,
__far *LPSTR, __near *NPSTR;
A particularly complicated use of typedef is to define a synonym for a “pointer to a function that returns type T.” For example, a typedef declaration that means “pointer to a function that takes no arguments and returns type void,” uses this code:
typedef void (*PVFN)();
The synonym can be handy in declaring arrays of functions that are to be invoked through a pointer:
#include <iostream.h>
#include <stdlib.h>
extern void func1(); // Declare 4 functions.
extern void func2(); // These functions are assumed to be
extern void func3(); // defined elsewhere.
extern void func4();
// Declare synonym for pointer to
typedef void (*PVFN)(); // function that takes no arguments
// and returns type void.
int main( int argc, char * argv[] )
{
// Declare an array of pointers to functions.
PVFN pvfn1[] = { func1, func2, func3, func4 };
// Invoke the function specified on the command line.
if( argc > 0 && *argv[1] > '0' && *argv[1] <= '4' )
(*pvfn1[atoi( argv[1] ) - 1])();
return 0;
}
Where void is used in the preceding typedef declaration, any set of type names can be substituted. This facilitates type checking. For example, a synonym for “pointer to a function that returns type int and takes two arguments, both of type const char *” can be written as follows:
typedef int (*PIFN)( const char *, const char * );
// Declare a pointer to a function to point to a string
// comparison function. At run time this can be changed
// to point to the stricmp function if a case-insensitive
// comparison is required.
PIFN pifnCompare = strcmp;
...
(*pifnCompare)( string1, string2 );
Redeclaration of typedef Names
The typedef declaration can be used to redeclare the same name to refer to the same type. For example:
// FILE1.H
typedef char CHAR;
// FILE2.H
typedef char CHAR;
// PROG.CPP
#include “file1.h”
#include “file2.h”
...
The program PROG.CPP includes two header files, both of which contain typedef declarations for the name CHAR. As long as both declarations refer to the same type, such redeclaration is acceptable.
A typedef cannot redefine a name that was previously declared as a different type. Therefore, if FILE2.H contains
// FILE2.H
typedef int CHAR;
the compiler issues an error because of the attempt to redeclare the name CHAR to refer to a different type. This extends to constructs such as:
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;
Use of typedef with Class Types
Use of the typedef specifier with class types is supported largely because of the ANSI C practice of declaring unnamed structures in typedef declarations. For example, many C programmers use the following coding practice:
typedef struct // Declare an unnamed structure and give it the
{ // typedef name POINT.
unsigned x;
unsigned y;
} POINT;
The advantage of such a declaration to the C programmer is that it enables declarations like:
POINT ptOrigin;
instead of:
struct point_t ptOrigin;
In C++, the difference between typedef names and real types (declared with the class, struct, union, and enum keywords) is more distinct. While the C practice of declaring a nameless structure in a typedef statement still works, it provides no notational benefits as it does in C.
The following code is illegal in C++ because the POINT function is not a type constructor; hence it must return a value.
typedef struct
{
POINT(); // Error: does not return a value.
unsigned x;
unsigned y;
} POINT;
The above example declares a class named POINT using the unnamed class typedef syntax. POINT is treated as a class name; however, the following restrictions apply to names introduced this way:
The name (the synonym) cannot appear after a class, struct, or union prefix.
The name cannot appear in the constructor names within a class declaration.
The name cannot appear in the destructor names within a class declaration.
In summary, this syntax does not provide any mechanism for inheritance, construction, or destruction.
Names declared using typedef occupy the same name space as other identifiers (except statement labels). Therefore, they cannot use the same identifier as a previously declared name, except in the case of a class-type declaration. Consider the following example:
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // Error: redefined.
The name-hiding rules that pertain to other identifiers also govern the visibility of names declared using typedef. Therefore, the following example is legal in C++:
typedef unsigned long UL; // Declare a typedef name, UL.
...
long Beep
{
unsigned int UL; // Redeclaration hides typedef name.
...
}
// typedef name “unhidden” here.