typedef
在C和C++编程语言中,typedef
是一个关键字。它用来对一个数据类型取一个别名,目的是为了使原始码更易于阅读和理解。它通常用于简化声明复杂的类型组成的结构 ,但它也常常在各种长度的整数资料类型中看到,例如size_t
和time_t
。
语法
[编辑]typedef
的语法是 : typedef typedeclaration;
[1]
创建 Length
作为 int
的别名 :
typedef int Length;
创建 PFI
作为一个指向“一个拥有两个 char *
当作参数并回传 int
的函数”的指针的别名
typedef int (*PFI)(char *, char *);
使用示例
[编辑]创建一个具有特别意义的资料类型
[编辑]typedef
会被用来指定一种资料类型的意义。
例如 : 以下示范一个普通的声明,速度及分数都被声明为int
int current_speed ;
int high_score ;
void congratulate(int your_score)
{
if (your_score > high_score)
...
通过typedef
来指定新的资料类型的意义:
typedef int km_per_hour ;
typedef int points ;
km_per_hour current_speed ; //"km_per_hour" is synonymous with "int" here,
points high_score ; //and thus, the compiler treats our new variables as integers.
void congratulate(points your_score) {
if (your_score > high_score)
...
前面两段代码运作状况一样,但是使用typedef
的第二段代码更清楚的表示了两个变量(score和speed),虽然资料类型都是int
,却是各自代表不同的意义,且他们的资料并不兼容。
但请注意,其清楚的表示不同意义只是对于工程师而言,C/C++的编译器认为两个变量都是int
时,并不会显示警告或错误,如: 以下代码,使用声明为速度的变量作为congratulate
函数的参数 :
void foo()
{
km_per_hour km100 = 100;
congratulate(km100);
但是,虽然在上面的代码中,编译器认为"km_per_hour"等于int
,但在使用前缀 unsigned
, long
, signed
时,两者并不能互换使用。
void foo() {
unsigned int a; // Okay
unsigned km_per_hour b; // Compiler complains
long int c; // Okay
long km_per_hour d; // Compiler complains
另一个例子:
int coxes;
int jaffa;
...
coxes++;
...
if (jaffa == 10)
...
现在来看以下代码:
typedef int Apple;
typedef int Orange;
Apple coxes;
Orange jaffa;
...
coxes++;
...
if (jaffa == 10)
...
这两段代码都做同样的一件事。第二个例子使用了 typedef
,使其更易于了解将要进行什么。也就是一个变量包含关于苹果的资讯,而另一个包含关于橘子的资讯。
简化声明语法
[编辑]struct var {
int data1;
int data2;
char data3;
};
此处用户定义一个数据类型 var
。
像这样建立一个 var
类型的变量,代码必须写为(注意,在 C++ 中声明一个 struct
时,同时也隐含了 typedef
,C 则没有):
struct var a;
在例子的最末处加入一行语句:
typedef struct var newtype;
现在要建立类型 var
的变量时,代码可以写为:
newtype a;
这样就更容易阅读了,因为不用再为每一个 var 类型的变量加上关键字 struct
。
也可以给数组使用 typedef
声明。
typedef BaseType NewType [arrSize];
这样就可以在声明一个 BaseType
类型和 arrSize
大小的新数组时,将代码写为:
NewType array;
与数组一起使用
[编辑]typedef
可以简单的跟数组一起使用。例如 :
typedef char arrType[6]; // type name: arrType
// new type: char[6]
arrType arr={1,2,3,4,5,6}; // same as: char arr[6]={1,2,3,4,5,6}
arrType *pArr; // same as: char (*pArr)[6];
在这里,arrType
是char[6]
的别称。而arrType *pArr;
则表示pArr
是一个指向存储char[6]
类型存储器的指针。
与指针一起使用
[编辑]可以使用typedef来定义一个新的指针类型 :
typedef int *intptr; // type name: intptr
// new type: int*
intptr ptr; // same as: int *ptr
在上面那段代码中,intptr
是一个 指针类型int*
的 新的别名。intptr ptr;
声明了一个变量(ptr
),其资料类型是int*
。如此一来ptr
就是一个 可以指向一段存储int
资料的存储器 的指针了。
使用typedef
来定义一个新的指针类型有时候会造成一些困惑 :
typedef int *intptr;
intptr cliff, allen; // both cliff and allen are int* type
intptr cliff2, *allen2; // cliff2 is int* type, but allen2 is int** type
// same as: intptr cliff2;
// intptr *allen2;
在上面的代码中,ntptr cliff, allen;
表示声明两个变量,其资料类型是int*
,而intptr *allan2
则使allen2
的类型成为int**
与结构指针一起使用
[编辑]struct Node {
int data;
struct Node *nextptr;
};
使用typedef
可以改写成如下 :
typedef struct Node Node;
struct Node {
int data;
Node *nextptr;
};
在C语言中,可以在一行中声明复数的变量,不管其是不是指针。不管如何,如果你要声明指针,必须在每个变量前面加上星号。
在下面的代码中,工程师可能会以为errptr
是一个指针,这个可能会引起一些错误。
struct Node *startptr, *endptr, *curptr, *prevptr, errptr, *refptr;
如果你用typedef
定义一个Node *
,这可以保证所有的变量都是一个指向一个structure type
的指针。
typedef struct Node* NodePtr;
...
NodePtr startptr, endptr, curptr, prevptr, errptr, refptr;
与函数指针一起使用
[编辑]
先看看以下这段尚未使用typedef
的代码:
int do_math(float arg1, int arg2) {
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);
这段代码可以被改写成如下:
typedef int (*MathFunc)(float, int);
int do_math(float arg1, int arg2) {
return arg2;
}
int call_a_func(MathFunc call_this) {
int output = call_this(5.5, 7);
return output;
}
int final_result = call_a_func(&do_math);
在这里,MathFunc
是一个指针,指向一个回传int
并以一个float
和一个int
作为参数使用的函数。当一个函数被当作参数使用时,如果少了typedef
它可能会变得难以了解。
以下是signal(3)
(来自FreeBSD)的函数原型:
void (*signal(int sig, void (*func)(int)))(int);
上面声明的函数相当的神秘,因为它没有清楚的显示它以什么函数当作参数,或回传了什么资料类型。一个初心者工程师甚至可能以为它接收一个int
作为参数,并不回传任何东西。但它其实接收了一个int
和一个function pointer
作为参数,并回传了一个function pointer
。它可以被改写成以下代码:
typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t func);
用来类型转换
[编辑]typedef
同时可以用来类型转换。例如:
typedef int (*funcptr)(double); // pointer to function taking a double returning int
funcptr x = (funcptr) NULL; // C or C++
funcptr y = funcptr(NULL); // C++ only
funcptr z = static_cast<funcptr>(NULL); // C++ only
左侧,funcptr
用来声明变量;右侧,funcptr
则用来转换值的类型。
如果少了typedef
,替换使用声明语法和类型转换语法是几乎不能做到的。例如:
void *p = NULL;
int (*x)(double) = (int (*)(double)) p; // This is legal
int (*)(double) y = (int (*)(double)) p; // Left-hand side is not legal
int (*z)(double) = (int (*p)(double)); // Right-hand side is not legal
外部链接
[编辑]- Cprogramming.com(页面存档备份,存于互联网档案馆) - 详细的讨论
引用
[编辑]- ^ typedef specifier. cppreference.com. [18 June 2016]. (原始内容存档于2018-03-10).