
Typedef在计算机编程语言中用于为复杂的声明定义简单的别名,这与宏定义有些不同。它本身就是存储类的关键字,不能和auto、extern、mutable、static、register等关键字出现在同一个表达式中。
Typedef的行为有点像#define宏,用它的实际类型替换同义词。区别在于typedef是在编译时解释的,所以允许编译器处理超出预处理器能力的文本替换。例如:
typedef int (*PF) (const char *,const char *);
这个声明引入了PF类型作为函数指针的同义词,它有两个const char * type的参数和一个int类型的返回值。如果要使用以下形式的函数声明,那么这个typedef是必不可少的:
PF寄存器(PF PF);
Register()的参数是PF类型的回调函数,返回与之前注册的名字签名相同的函数的地址。深呼吸。让我展示一下我们是如何在没有typedef的情况下实现这个声明的:
int(* Register(int(* pf)(const char *,const char *))
(const char *,const char *);
很少有程序员明白这意味着什么,更不用说这种无法理解的代码所带来的出错风险了。显然,这里使用typedef不是特权,而是必须。怀疑论者可能会问,“好吧,有人会写这样的代码吗?”快速浏览一下显示signal()函数的头文件,该函数具有相同的接口。注意,寄存器被定义为一个函数,而不是函数指针。如果定义为函数指针,应该这样写:int(*(* register)(int(* pf)(const char *,const char *)(const char *,const char *);
Typedef和存储类说明符。
这是不是有点让人吃惊?typedef是一个存储类关键字,类似于auto、extern、mutable、static和register。这并不是说typedef真的会影响对象的存储特性;只是意味着从句子构成来说,typedef声明看起来像static、extern等类型的变量声明。下面将导致第二个陷阱:
typedef寄存器int FAST _ COUNTER//错误
编译失败。问题是在声明中不能有多个存储类关键字。Register(或任何其他存储类关键字)不能在typedef声明中使用,因为符号typedef已经占用了存储类关键字的位置。
typedef的四种用法
使用1:
定义一种别名,而不仅仅是简单的宏替换。可用于同时声明多个指针类型的对象。例如:
char* pa,Pb;//这大部分都不符合我们的本意。它只声明了一个指向字符变量的指针。
//和一个字符变量;
以下是可行的:
typedef char * PCHAR//一般用大写。
PCHAR pa,Pb;//可行,声明了两个指向字符变量的指针。
虽然:
char *pa,* pb
也是可行的,但是相对来说不如typedef直观,尤其是需要大量指针的地方,typedef更方便。
使用2:
在旧C代码中使用(有多老了)来帮助struct。在前面的代码中,当声明一个新的struct对象时,必须带struct,即形式:struct结构名对象名,如:
[cpp]查看普通copystruct标记点1
{
int x;
int y;
};
结构标记点p1
在C中,可以直接写:结构名对象名,即:
标记点p1
估计有人觉得经常多写一个struct太麻烦了,于是发明了:
[cpp]查看普通copytypedef结构标记点
{
int x;
int y;
}点;
点P1;//这样比原来的方式少写一个struct,更方便,尤其是大量使用的时候。
或许,在C中,typedef的这个用处并不是很大,但是了解它对旧代码的掌握还是有帮助的。毕竟,我们可能会遇到项目早期遗留下来的代码。
使用3:
使用typedef定义独立于平台的类型。
例如,定义一个名为REAL的浮点类型,让它表示目标平台上精度最高的类型1:
typedef长双实数;
在不支持long double的第二个平台上,将其更改为:
typedef双实数;
在第三个甚至不支持double的平台上,改成:
typedef float REAL
换句话说,跨平台的时候,只需要改变typedef本身,不需要对其他源代码做任何改变。
这种技术广泛应用于标准库,比如size _ t。
此外,typedef比macro更健壮,因为它定义了一种新类型的别名,而不是简单的字符串替换(尽管macro有时也能完成上述目的)。
使用4:
为复杂声明定义新的简单别名。方法是:逐步将原语句中一些复杂的带有别名的语句替换掉,以此类推,将带有变量名的部分留到最后替换,得到原语句最简化的版本。示例:
1.原语句:int *(A[5])(int,char *);
变量被命名为a,所以只需用新的别名pFun替换a:
typedef int * *(pFun)(int,char *);
最初陈述的最简单版本:
pFun a[5];
2.原语句:void(* b[10])(void(*));
变量名是b,先把右边括号里的替换掉,pFunParam是别名1:
typedef void(* pfun param)();
替换左边的变量b,pFunx就是别名2:
typedef void(* pFunx)(pfun param);
最初陈述的最简单版本:
pFunx b[10];
3.原语句:doube(*)(* e)[9];
变量名为e,先替换左边部分,pFuny为别名1:
typedef double(* pFuny)();
替换右边的变量e,pFunParamy就是别名二。
typedef pFuny(* pFunParamy)[9];
最初陈述的最简单版本:
pFunParamy e;
理解适用于复杂语句的“左右规则”;
从变量名开始,先右转,再左转,遇到圆括号就转阅读方向;分析完括号后跳出括号,或者先按右再按左,以此类推,直到分析完整个语句。示例:
int(* func)(int * p);
先找到变量名func,外面有一对括号,左边有*号,说明func是指针;然后跳出括号,先看右边,再遇到括号,说明(*func)是函数,所以func是指向这类函数的指针,也就是函数指针。这种函数有int*类型的参数,返回值类型是int。
int(* func[5])(int *);
func右边是[]运算符,表示func是一个有5个元素的数组;func的左边有一个*号,表示func的元素是指针(注意这里的*号不是func的修饰符,而是func [5]的修饰符,因为[]运算符的优先级比*号高,func先和[]组合)。跳出这个括号,向右看,遇到圆括号,说明func数组的元素是一个函数类型的指针,它指向的函数有一个int*类型的参数,返回值类型是int。
你也可以记住两种模式:
类型(*).)函数指针
类型(*) []数组指针
编号二、两个陷阱
陷阱1:
记住,typedef是定义类型的新别名。与宏不同,它不是简单的字符串替换。例如:
首先定义:
typedef char * PSTR;
然后:
int mystrcmp(常量PSTR,常量PSTR);
const PSTR实际上等价于const char*?不,它实际上相当于char* const。
原因是const赋予整个指针本身恒常性,即const指针char* const形成。
简单来说,只要记住当const和typedef一起出现时,typedef就不会是简单的字符串替换。
陷阱2:
Typedef在语法上是存储类(如auto、extern、mutable、static、register等)的关键字。),尽管它并不真正影响对象的存储特征,例如:
typedef静态int INT2//不可行
编译将失败,并提示您“指定了多个存储类”。
以上信息来自:http://blog.sina.com.cn/s/blog_4826f7970100074k.html作者:红龙
否三、 Typedef和#define之间的区别
案例1:
一般来说,typedef比#define好,尤其是有指针的时候。看看这个例子:
[cpp]查看plain copytypedef char * pStr1
#定义pstr 2 char *;
pStr1 s1,S2;
pStr2 s3、S4;
在上面的变量定义中,s1、s2、s3都定义为char *,而s4定义为char,并不是我们预期的指针变量。根本原因是#define只是一个简单的字符串替换,而typedef给了一个类型新的名字。
案例二:
编译器将在下面的代码中报告一个错误。你知道哪种说法是错的吗?
[cpp]查看plain copytypedef char * pStr
char string[4]="ABC";
const char *p1=字符串;
const pStr p2=string
P1;
p2;
P2犯了个错误。这个问题再次提醒我们,typedef不同于#define,它不是简单的文本替换。上面代码中的Constpsttrp2不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量的只读限制,只是这里变量p2的数据类型是我们自己定义的,而不是系统固有的类型。所以const pStr p2意味着数据类型为char *的变量p2被限制为只读,所以p2是错误的。
第四部分信息:使用typedef抑制劣质代码
作者:丹尼卡列夫
编译:MTT工作室
原始源代码:使用typedef来抑制错误代码
摘要:Typedef声明有助于创建与平台无关的类型,甚至隐藏复杂和难以理解的语法。无论如何,使用typedef都能给代码带来意想不到的好处。通过本文,您可以学习使用typedef来避免缺陷,从而使代码更加健壮。
Typedef声明,简称typedef,为现有类型创建一个新名称。例如,人们经常使用typedef来编写更漂亮、可读性更好的代码。所谓美观,就是typedef可以隐藏笨拙的语法结构和平台相关的数据类型,从而增强可移植性和未来的可维护性。本文将尽力揭示typedef的强大功能以及如何避免一些常见的陷阱。
问:如何创建独立于平台的数据类型并隐藏笨拙和难以理解的语法?
答:使用typedefs为现有类型创建同义词。
定义一个容易记忆的类型名。
Typedef最常用于创建易于记忆的类型名,用于存档程序员的意图。该类型出现在“typedef”关键字右侧声明的变量名中。例如:
typedef int size
这个声明定义了一个int命名的size的同义词。请注意,typedef不创建新类型。它只是向现有类型添加一个同义词。您可以在任何需要int的上下文中使用size:
空度量(大小* PSZ);大小数组[4];size len=file . getlength();STD:vector 《size》 vs;
Typedef还可以屏蔽匹配类型,如指针和数组。例如,您不必重复定义包含81个字符元素的数组,如下所示:
充电线[81];char text[81];
定义一个typedef,每当你想使用相同类型和大小的数组时,你可以这样做:
typedef字符行[81];行文本,第二行;getline(文本);
类似地,指针语法可以隐藏如下:
typedef char * pstrint mystrcmp(pstr,pstr);
这将把我们带到第一个typedef陷阱。标准函数strcmp()有两个“constchar *”类型的参数。因此,可能会误导人们将mystrcmp()声明为:
int mystrcmp(const pstr,const pstr);
这是不对的。按顺序,“constpstr”解释为“char * const”(指向char的const指针),而不是“const char *”(指向常量char的指针)。这个问题很容易解决:
typedef const char * cpstrint mystrcmp(cpstr,cpstr);//现在是正确的。
记住:每当你为一个指针声明一个typedef的时候,你应该在最后的typedef名称上加一个const,这样指针本身就是一个常量,而不是一个对象。
代码简化
上面讨论的Typedef的行为有点像#define宏,用它的实际类型替换同义词。区别在于typedef是在编译时解释的,所以允许编译器处理超出预处理器能力的文本替换。例如:
typedef int (*PF) (const char *,const char *);
这个声明引入了PF类型作为函数指针的同义词,它有两个const char * type的参数和一个int类型的返回值。如果要使用以下形式的函数声明,那么这个typedef是必不可少的:
PF寄存器(PF PF);
Register()的参数是PF类型的回调函数,返回与之前注册的名字签名相同的函数的地址。深呼吸。让我展示一下我们是如何在没有typedef的情况下实现这个声明的:
int(* Register(int(* pf)(const char *,const char *))(const char *,const char *);
很少有程序员明白这意味着什么,更不用说这种无法理解的代码所带来的出错风险了。显然,这里使用typedef不是特权,而是必须。怀疑论者可能会问,“好吧,有人会写这样的代码吗?”快速看一下头文件《csinal》,它揭示了signal()函数,一个具有相同接口的函数。
Typedef和存储类说明符。
这是不是有点让人吃惊?typedef是一个存储类关键字,类似于auto、extern、mutable、static和register。这并不意味着typedef会真正影响对象的存储特性;只是意味着从句子构成来说,typedef声明看起来像static、extern等类型的变量声明。下面将导致第二个陷阱:
typedef寄存器int FAST _ COUNTER//错误
编译失败。问题是在声明中不能有多个存储类关键字。Register(或任何其他存储类关键字)不能在typedef声明中使用,因为符号typedef已经占用了存储类关键字的位置。
促进跨平台开发
Typedef还有一个重要的用途,就是定义与机器无关的类型。例如,您可以定义一个名为REAL的浮点类型,它可以在目标机器上获得最高的精度:
typedef长双实数;
在不支持long double的机器上,typedef将如下所示:
typedef双实数;
此外,在一台甚至不支持double的机器上,typedef将如下所示:
typedef float REAL
您可以在任何平台上使用实类型编译该应用程序,而无需对源代码进行任何更改。唯一要改变的是typedef本身。大多数情况下,即使是这种微小的改变,也可以通过奇妙的条件编译自动实现。不是吗?Typedef被标准库广泛用于创建这种平台无关的类型:size_t、ptrdiff和fpos_t就是例子。此外,STD: String和STD: ofstream等typedef还隐藏了冗长且难以理解的模板专门化语法,如basic_string 《char, char_traits《char》、allocator 《char》和basic_ofstream 《char, char_traits《char》。
以上转自:http://www.kuqin.com/language/20090322/41866.html
typedef结构的问题
(1)、typedef的最简单用法
typedef长字节_ 4;
给已知的数据类型long起一个新名字,叫做byte_4。
(2) typedef与结构相结合。
typedef struct tagMyStruct
{
int iNum
长度长;
} MyStruct
这条语句实际上完成了两个操作:
1)定义新的结构类型
结构标记结构
{
int iNum
长度长;
};
解析:tagMyStruct叫“tag”,即“tag”,其实是一个临时名称。struct关键字和tagMyStruct共同构成了这个结构类型,不管有没有typedef,这个结构都是存在的。
我们可以用struct tagMyStruct varName来定义变量,但是用tag mysterious Varname来定义变量是错误的,因为struct和tag mystery一起可以表示一个结构类型。
2) typedef给这个新结构起了个名字,叫MyStruct。
typedef struct tagmy struct my struct;
所以MyStruct实际上等同于struct tagMyStruct,我们可以用MyStruct varName来定义变量。
3)、标准做法:
结构标记节点
{
char * pItem
struct tagNode * pNext
};
typedef struct tagNode * pNode
3.typedef # define的问题
有两种方法可以定义pStr数据类型。两者有什么区别?哪个更好?
typedef char * pStr
#定义pStr char *;
答案和分析:
一般来说,typedef比#define好,尤其是有指针的时候。看看这个例子:
typedef char * pStr1
#定义pStr2字符*
pStr1 s1,S2;
pStr2 s3、S4;
在上面的变量定义中,s1、s2、s3都定义为char *,而s4定义为char,并不是我们预期的指针变量。根本原因是#define只是一个简单的字符串替换,而typedef给了一个类型新的名字。
在上面的例子中,define语句必须写成pStr2 s3,* s4这个可以正常进行。
#define的用法示例:
#定义f(x) x*x
主( )
{
int a=6,b=2,c;
c=f(a)/f(b);
printf("%d //n",c);
}
以下程序的输出是:36。
为此,在许多C语言编程规范中,当使用#define定义时,如果定义中包含表达式且必须使用括号,则上述定义应定义如下:
#定义f(x) (x*x)
当然,如果用typedef,就不存在这个问题。
4.typedef # define的另一个例子
编译器将在下面的代码中报告一个错误。你知道哪种说法是错的吗?
typedef char * pStr
char string[4]="ABC";
const char *p1=字符串;
const pStr p2=string
P1;
p2;
答案和分析:
P2犯了个错误。这个问题再次提醒我们,typedef不同于#define,它不是简单的文本替换。上面代码中的Constpsttrp2不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量的只读限制,只是这里变量p2的数据类型是我们自己定义的,而不是系统固有的类型。所以const pStr p2意味着数据类型为char *的变量p2被限制为只读,所以p2是错误的。
关于#define和typedef的扩展
1) #define宏定义有一个特别的好处:可以使用#ifdef、#ifndef等。进行逻辑判断,也可以用#undef取消定义。
2) typedef还有一个特别的优点:它符合作用域规则,typedef定义的变量类型的作用域仅限于被定义的函数或文件(取决于变量定义的位置),而宏定义不具备这个特性。
5.typedef复杂变量声明
在编程实践中,尤其是在阅读别人的代码时,经常会遇到复杂的变量声明。使用typedef进行简化有其自身的价值,例如:
下面是三个变量的声明。我想用typdef分别为它们定义别名。我该怎么办?
》1:int *(*a[5])(int,char *);
》2:void(* b[10])(void(*));
》3.double(*)(* pa)[9];
答案和分析:
为复杂变量建立类型别名的方法非常简单。你只需要把传统变量声明表达式中的变量名替换成类型名,然后在语句开头加上关键字typedef。
》1:int *(*a[5])(int,char *);
//pFun是我们构建的类型别名。
typedef int * *(pFun)(int,char *);
//用定义好的新类型声明一个对象,相当于int *(a[5])(int,char *);
pFun a[5];
》2:void(* b[10])(void(*));//此蓝色部分为个人理解,未找到原始出处。
//首先为上面表达式的蓝色部分声明一个新类型。
typedef void(* pfun param)();
//整体声明一个新类型。
typedef void(* pFun)(pFun param);
//用定义好的新类型声明一个对象,相当于void(* b[10])(void(*));
pFun b[10];
》3.double(*(* pa)[9])();//此蓝色部分为个人理解,未找到原始出处。
//首先为上面表达式的蓝色部分声明一个新类型。
typedef double(* pFun)();
//整体声明一个新类型。
typedef pFun(* pFun param)[9];
//用定义好的新类型声明一个对象,相当于Double(*(* PA)[9])();
pFunParam pa









