typedef是什么意思啊(typedef是什么意思)

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