typedef is a reserved keyword in the programming languages C, C++, and Objective-C. It is used to create an additional name ( alias) for another type system, but does not create a new type, except in the obscure case of a Type qualifier typedef of an array type where the typedef qualifiers are transferred to the array element type. As such, it is often used to simplify the syntax of declaring complex consisting of struct and , although it is also commonly used to provide specific descriptive type names for integer data types of varying sizes.
In the C standard library and in POSIX specifications, the identifier for the typedef definition is often suffixed with , such as in size_t and time_t. This is practiced in other coding systems, although POSIX explicitly reserves this practice for POSIX data types.
void congratulate(int your_score) {
if (your_score > high_score) {
// ...
}
}
may be expressed by declaring context specific types:
// `km_per_hour` is synonymous with `int` here, and thus, the compiler treats
// our new variables as integers.
km_per_hour current_speed;
points high_score;
void congratulate(points your_score) {
if (your_score > high_score) {
// ...
}
}
Both sections of code execute identically. However, the use of typedef declarations in the second code block makes it clear that the two variables, while representing the same data type , store different or incompatible data. The definition in of indicates to the programmer that (or any other variable not declared as a ) should not be passed as an argument. This would not be as apparent if both were declared as variables of datatype. However, the indication is for the programmer only; the C/C++ compiler considers both variables to be of type and does not flag type mismatch warnings or errors for "wrong" argument types for in the code snippet below:
km_per_hour km100 = 100;
congratulate(km100);
}
int data1;
char data2;
};
defines the data type . In C, absent a typedef, the full type name must be used to declare variables of that type:
A typedef declaration can provide a simpler type name that does not include . For example, with the type declaration
the variable declaration can be reduced to:
The structure declaration and typedef may also be combined into a single declaration:
int data1;
char data2;
} newtype;
, including when no tag is declared:
int data1;
char data2;
} newtype;
In C++, unlike in C, tags of , , , and types (such as the "" above) automatically can be used by themselves as aliases for the full type names, very much as if there were explicit typedefs declaring so at the point of the type declaration:
Indeed, for , , and types, C++ calls the tag a class name.
The correspondence between this C++ feature and typedef is very strong, extending to the fact that it is possible to shadow the simple type name in a nested scope by declaring it as the identifier of another kind of entity. In such a case, the C-style full type name (an "elaborated type specifier") can still be used to refer to the class or enum type.
In C++, then, can be used anywhere that can be used, as long as there are no other declarations of these identifiers. The reverse is not true, however, for C++ requires the class name for some purposes, such as the names of constructor methods.
A notorious example where even C++ needs the keyword is the POSIX stat system call that uses a struct of the same name in its arguments:
// ...
}
Here both C as well as C++ need the keyword in the parameter definition.
intptr ptr;
// Same as:
// int *ptr;
is a new alias with the pointer type . The definition, , defines a variable with the type . So, is a pointer which can point to a variable of type .
Using typedef to define a new pointer type may sometimes lead to confusion. For example:
// Both 'cliff' and 'allen' are of type int*.
intptr cliff, allen;
// 'cliff2' is of type int*, but 'allen2' is of type int**.
intptr cliff2, *allen2;
// Same as:
// intptr cliff2;
// intptr *allen2;
Above, means defining 2 variables with type for both. This is because a type defined by typedef is a type, not an expansion. In other words, , which is the type, decorates both and . For , the type decorates the and . So, is equivalent to 2 separate definitions, and . means that is a pointer pointing to a memory with type. Shortly, has the type, .
const intptr ptr = NULL;
// This is equivalent to:
// int *const ptr = NULL; // Constant pointer to an integer.
Since it is a constant pointer, it must be initialized in the declaration.
int data;
struct Node *nextptr;
};
Using typedef, the above code can be rewritten like this:
struct Node {
int data;
Node *nextptr;
};
In C, one can declare multiple variables of the same type in a single statement, even mixing structure with pointer or non-pointers. However, one would need to prefix an asterisk to each variable to designate it as a pointer. In the following, a programmer might assume that was indeed a , but a typographical error means that is a . This can lead to subtle syntax errors.
By defining the typedef , it is assured that all variables are structure pointer types, or say, that each variable is a pointer type pointing to a Struct.
NodePtr startptr, endptr, curptr, prevptr, errptr, refptr;
return arg2;}
int call_a_func(int (*call_this)(float, int)) {
int output = call_this(5.5, 7);
return output;}
int final_result = call_a_func(&do_math);
The preceding code may be rewritten with typedef specifications:
int do_math(float arg1, int arg2) {
int call_a_func(MathFunc call_this) {
int final_result = call_a_func(&do_math);
return arg2;
}
int output = call_this(5.5, 7);
return output;
}
Here, is the new alias for the type. A is a pointer to a function that returns an integer and takes as arguments a float followed by an integer.
When a function returns a function pointer, it can be even more confusing without typedef. The following is the function prototype of signal(3) from FreeBSD:
The function declaration above is cryptic as it does not clearly show what the function accepts as arguments, or the type that it returns. A novice programmer may even assume that the function accepts a single as its argument and returns nothing, but in reality it also needs a function pointer and returns another function pointer. It can be written more cleanly:
sighandler_t signal(int sig, sighandler_t func);
arrType arr = {1, 2, 3, 4, 5, 6};
arrType *pArr;
// Same as:
// char arr6 = {1, 2, 3, 4, 5, 6};
// char (*pArr)6;
Here, is the new alias for the type, which is an array type with 6 elements. For , is a pointer pointing to the memory of the type.
// Valid in both C and C++.
funcptr x = (funcptr) NULL;
// Only valid in C++.
funcptr y = funcptr(NULL);
funcptr z = static_cast
is used on the left-hand side to declare a variable and is used on the right-hand side to cast a value. Thus, the typedef can be used by programmers who do not wish to figure out how to convert definition syntax to type cast syntax.
Without the typedef, it is generally not possible to use definition syntax and cast syntax interchangeably. For example:
// This is legal.
int (*x)(double) = (int (*)(double)) p;
// Left-hand side is not legal.
int (*)(double) y = (int (*)(double)) p;
// Right-hand side is not legal.
int (*z)(double) = (int (*p)(double));
for (std::vector
std::pair
// ...
}
and
values_t values;
for (values_t::const_iterator i = values.begin(); i != values.end(); ++i)
{
value_t const & t = *i;
// ...
}
C++11 introduced the possibility to express typedefs with instead of . For example, the above two typedefs could equivalently be written as
However, if one is willing to accept in lieu of , then it is possible to achieve the desired result via a typedef within an otherwise unused templated class or struct:
// Declare a variable of type `std::pair // Prevent instantiation of `stringpair
public:
// Make `stringpair
};
In C++11, templated typedefs are added with the following syntax, which requires the keyword rather than the keyword. (See template aliases.)
// Declare a variable of type `std::pair
In many statically typed functional languages, like Haskell, Miranda, OCaml, etc., one can define type synonyms, which are the same as typedefs in C. An example in Haskell:
This example has defined a type synonym as an integer type.
In Seed7 the definition of a constant type is used to introduce a synonym for a type:
const type: myVector is array integer;
In Swift, one uses the keyword to create a typedef:
C# contains a feature which is similar to the typedef or the syntax of C++.
In D the keyword allows to create type or partial type synonyms.
Some programmers are opposed to the extensive use of typedefs. Most arguments center on the idea that typedefs simply hide the actual data type of a variable. For example, Greg Kroah-Hartman, a Linux kernel hacker and documenter, discourages their use for anything except function prototype declarations. He argues that this practice not only unnecessarily obfuscates code, it can also cause programmers to accidentally misuse large structures thinking them to be simple types.
|
|