版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、c语言中typedef 的用法c语言中typedef的用法的用法你知道吗?下面就跟你们详细介 绍下c语言中typedef的用法的用法,希望对你们有用。c语言中typedef的用法的用法如下:一.基本概念剖析int* (*a5)(i nt, char*);/# 1void (*b10) (void (*)(); /# 2double(*)() (*pa)9;# 31. C语言中函数声明和数组声明。函数声明一般是这样:int fun (i nt, double);对应函数指针(pointer to function)的声明是这样:int (*pf) (int, double);可以这样使用:pf
2、= &fun;赋值(assignment ) 操作(*pf)(5, 8.9);/函数调用操作也请注意,C语言本身提供了一种简写方式如下:pf = fun;/ 赋值(assignment ) 操作pf(5, 8.9);/ 函数调用操作不过我本人不是很喜欢这种简写,它对初学者带来了比较多的迷 惑。数组声明一般是这样:int a5;对于数组指针(pointer to array )的声明是这样:int (*pa)5;可以这样使用:pa = &a ; / 赋值(assignment ) 操作int i = (*pa)2;/ 将 a2赋值给 i;2. 有了上面的基础,我们就可以对付开头的
3、三只纸老虎了 !:)这 个时候你需要复习一下各种运算符的优先顺序和结合顺序了,顺便找本书看看就够了。# 1 : int* (*a5)(int, char*);首先看到标识符名a,“优先级大于“*”,a与“5”先结合。 所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,指针指向“(int, char*) ”,对,指向一个函数,函数参数是“ int, char* ”,返回值是“ int* ”。完毕,我们干掉了第一个纸老虎。:)# 2: void (*b10) (void (*)();b是一个数组,这个数组有10个元素,每一个元素都是一个指 针,指针指向一个函数,函数参数是“ void
4、(*)()”【注1 ,返回值是“void ”。完毕!注1:这个参数又是一个指针,指向一个函数,函数参数为空, 返回值是“ void ”。# 3: double(*)()(*pa)9;pa是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是“ double(*)() ”【也即一个指针,指向一个函数,函数参数为空,返回值是“ double# 1 : int* (*a5)(int, char*);typedef int* (*PF)(int, char*);/PF是一个类型别名【注 2 】。PF a5;/ 跟 int* (*a5)(int, char*); 的效果一样!注2 :很多初学者
5、只知道typedef char* pchar ;但是对于typedef的其它用法不太了解。Stephen Blaha 对typedef用法做过 一个总结:“建立一个类型别名的方法很简单,在传统的变量声明表 达式里用类型名替代变量名,然后把关键字typedef加在该语句的开 头”。# 2: void (*b10)(void (*)();typedef void (*pfv)();typedef void (*pf_tak in g_pfv)(pfv);pf_taking_pfv b10; / 跟 void (*b10) (void (*)(); 的效果一 样!# 3. double(*)()(*
6、pa)9;typedef double(*PF)();typedef PF (*PA)9;PA pa; / 跟 doube(*)()(*pa)9;的效果一样!3.const和volatile在类型声明中的位置。在这里我只说con st , volatile是一样的!【注3 注3 :顾名思义,volatile修饰的量就是很容易变化,不稳定的量,它可能被其它线程,操作系统,硬件等等在未知的时间改变,所以它被存储在内存中,每次取用它的时候都只能在内存中去读 取,它不能被编译器优化放在内部寄存器中。类型声明中con st用来修饰一个常量,我们一般这样使用:const 在前面:const int ;in
7、t 是 constconst char*;/char 是 constchar* con st;/*(指针)是 constconst char* const;/char禾口 *都是 const对初学者,co nst char*和char* con st 是容易混淆的。这需要 时间的历练让你习惯它。上面的声明有一个对等的写法:con st在后面:int const ; /int 是 constchar const*;/char是 constchar* con st;/*(指针)是 constchar con st* con st;/char和口 * 都是 const第一次你可能不会习惯,但新事物如
8、果是好的,我们为什么要拒 绝它呢?:)const在后面有两个好处:A. con st所修饰的类型正好是在它前面的那一个。如果这个好处还不能让你动心的话,那请看下一个!B .我们很多时候会用到typedef的类型别名定义。比如typedef char* pchar,如果用const来修饰的话,当con st在前面的时候,就是 co nst pchar,你会以为它就是 con st char* ,但是你错了,它的真实含义是 char* con st。是不是让你大吃一惊!但如果你采用const在后面的写法,意义 就怎么也不会变,不信你试试!不过,在真实项目中的命名一致性更重要。你应该在两种情况下都能
9、适应,并能自如的转换,公司习惯,商业利润不论在什么时候都应该优先考虑!不过在开始一个新项目的时候,你可以考虑优先使用 const在后面的习惯用法。二.Typedef声明有助于创建平台无关类型,甚至能隐藏复杂和 难以理解的语法。不管怎样,使用typedef能为代码带来意想不到的好处,通过 本文你可以学习用typedef避免缺欠,从而使代码更健壮。typedef声明,简称typedef,为现有类型创建一个新的名字。 比如人们常常使用typedef来编写更美观和可读的代码。所谓美观,意指typedef能隐藏笨拙的语法构造以及平台相关 的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全
10、力来揭示 typedef强大功能以及如何避免一 些常见的陷阱,如何创建平台无关的数据类型,隐藏笨拙且难以理解 的语法.typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于typedef关键 字右边。例如:typedef int size;此声明定义了一个int的同义字,名字为 size。注意typedef并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要int的上下文中使用size:void measure(size * psz);size array4;size len 二 file.getle ngth();type
11、def还可以掩饰复合类型,如指针和数组。例如,你不用象下面这样重复定义有81个字符元素的数组:char lin e81; char text81;定义一个typedef,每当要用到相同类型和大小的数组时,可以 这样:typedef char Lin e81;Line text, sec on dli ne;getl in e(text);同样,可以象下面这样隐藏指针语法:typedef char * pstr;int mystrcmp(pstr, pstr);这里将带我们到达第一个typedef陷阱。标准函数strcmp() 有两个con st char *类型的参数。因此,它可能会误导人们象
12、下面这 样声明:int mystrcmp(c onst pstr, const pstr);这是错误的,事实上,const pstr被编译器解释为char * const(一个指向char的常量指针),而不是con st char * (指向常量 char的指针)。这个问题很容易解决:typedef const char * cpstr;int mystrcmp(cpstr, cpstr);上面讨论的typedef行为有点像#define宏,用其实际类型 替代同义字。不同点是typedef在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。例如:typedef int (*PF) (
13、const char *, const char *);这个声明引入了 PF类型作为函数指针的同义字,该函数有两个 con st char * 类型的参数以及一个int类型的返回值。如果要使用 下列形式的函数声明,那么上述这个 typedef是不可或缺的:PF Register(PF pf);Register。的参数是一个PF类型的回调函数,返回某个函数的 地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一 下如果不用typedef,我们是如何实现这个声明的:int (*Register (i nt (*pf)(c onst char *, const char *) (const
14、char *, const char *);很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用typedef不是一种特权,而是一种必需。typedef 就像 auto,extern ,mutable ,static,和register 一样,是一个存储类关键字。这并不是说typedef会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象static,extern等类型的变量声 明。下面将带到第二个陷阱:typedef register int FAST_COUNTER; /错误编译通不过问题出在你不能在声明中有多个存储类关键字。因为符
15、号typedef已经占据了存储类关键字的位置,在typedef声明中不能用register (或任何其它存储类关键字)。typedef有另外一个重要的用途,那就是定义机器无关的类型, 例如,你可以定义一个叫REAL的浮点类型,在目标机器上它可以获得最高的精度:typedef long double REAL;在不支持long double 的机器上,该typedef 看起来会是下 面这样:typedef double REAL;并且,在连double都不支持的机器上,该typedef看起来会 是这样:typedef float REAL;你不用对源代码做任何修改,便可以在每一种平台上编译这个使
16、 用REAL类型的应用程序。唯一要改的是 typedef 本身。在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条 件编译来自动实现。不是吗?标准库广泛地使用typedef来创建这样的平台无关类型:size_t, ptrdiff 和fpos_t就是其中的例子。此外,象 std:string 禾口 std:ofstream 这样的 typedef 还隐 藏了长长的,难以理解的模板特化语法,例如:basic_string ,allocator>禾口 basic_ofstream>。用途一:定义一种类型的别名,而不只是简单的宏替换。可以用作同时声 明指针型的多个对象。比如:char
17、* pa, pb; /这多数不符合我们的意图,它只声明了一个指向字符变量的指针,/和一个字符变量;以下则可行:typedef char* PCHAR; /一般用大写PCHAR pa, pb; /可行,同时声明了两个指向字符变量的指针虽然:char *pa, *pb;也可行,但相对来说没有用typedef的形式直观,尤其在需要大 量指针的地方,typedef的方式更省事。用途二:用在旧的C代码中(具体多旧没有查),帮助struct。以前的代 码中,声明struct新对象时,必须要带上struct ,即形式为:struct 结构名对象名,如:struct tagPOINTIint x;int y;
18、;struct tagPOINTI p1;而在C+中,则可以直接写:结构名 对象名,即:tagPOINTI p1;估计某人觉得经常多写一个struct太麻烦了,于是就发明了: typedef struct tagPOINTint x;int y;POINT;POINT p1; /这样就比原来的方式少写了一个 struct,比较省事,尤其在大量使用的时候或许,在C+中,typedef的这种用途二不是很大,但是理解 了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能 会遇到较早些年代遗留下来的代码。用途三:用typedef来定义与平台无关的类型。比如定义一个叫 REAL的浮点类型,在目标
19、平台一上,让它表 示最高精度的类型为:typedef long double REAL;在不支持long double的平台二上,改为:typedef double REAL;在连double 都不支持的平台三上,改为:typedef float REAL;也就是说,当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改。标准库就广泛使用了这个技巧,比如 size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字 符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用 途)。用途四:为复杂的声明定义一个新的简单的别名。 方法是:在原来的声明 里逐步用别名替
20、换一部分复杂声明,如此循环,把带变量名的部分留 到最后替换,得到的就是原声明的最简化版。举例:1. 原声明:int *(*a5)(int, char*);变量名为a,直接用一个新别名pFun替换a就可以了:typedef int *(*pF un )(i nt, char*);原声明的最简化版:pFun a5;2. 原声明:void (*b10) (void (*)();变量名为b,先替换右边部分括号里的,pFunParam为别名一:typedef void (*pF un Param)();再替换左边的变量b,pFunx为别名二:typedef void (*pF un x)(pF un P
21、aram);原声明的最简化版:pFu nx b10;3. 原声明:doube(*)() (*e)9;变量名为e,先替换左边部分,pFuny为别名一:typedef double(*pF uny)();再替换右边的变量e,pFunParamy为别名二typedef pFuny (*pF un Paramy)9;原声明的最简化版:pFun Paramy e;理解复杂声明可用的“右左法则”:从变量名看起,先往右,再 往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号, 还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:int (*fun c)(i nt *p);首先找到变量名func ,外面有一对圆括号,而且左边是一个*号, 这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到 圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数 的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是 int。int (*fun c5)(i nt *);func右边是一个运算符,说明func是具有5个元素的数组; func的左边有一个*,说明func的元素是指针(注意这里的*不是修 饰func,而是
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 秦皇岛市抚宁县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 甘孜藏族自治州雅江县2025-2026学年第二学期五年级语文第五单元测试卷(部编版含答案)
- 太原市尖草坪区2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 青岛市市北区2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 吴忠市同心县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 宝鸡市陇县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 汽修厂营销策划方案
- 深度解析(2026)《CBT 13-2007船舶产品通 用图样和技术文件编号》
- 深度解析(2026)《2026年机场、港口等大型交通枢纽分布式光伏的融资特点与安全规范》
- 求文言文试题及答案
- 安捷伦GC仪器操作步骤
- 牙体代型制备与修整(口腔固定修复工艺课件)
- GB/T 38658-20203.6 kV~40.5 kV交流金属封闭开关设备和控制设备型式试验有效性的延伸导则
- 美学第六讲日常生活美
- GA/T 1047-2013道路交通信息监测记录设备设置规范
- 2023年成都天府新区投资集团有限公司招聘笔试模拟试题及答案解析
- 通用设备经济寿命参考年限表
- DBJ51-T 194-2022 四川省城镇房屋白蚁预防工程药物土壤屏障检测和评价技术标准
- 三节三爱主题班会教学课件
- 城市超标洪水防御预案
- 安全生产应知应会培训课件
评论
0/150
提交评论