typedef
![本页使用了标题或全文手工转换](http://images.weserv.nl/?url=//upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Zh_conversion_icon_m.svg/35px-Zh_conversion_icon_m.svg.png)
在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).