typedef的用法

《C语言程序设计:现代方法》看到第七章——基本类型,对书上7.6节的关于typedef的用法说明不太清楚,感觉书上的两页介绍不够详细,在网上再找了些资料,做下汇总:

typedef是为现有类型(包含变量类型,指针/数组类型,结构类型和函数类型)创建一个新的名字,以增加代码的可读性,可维护性和可移植性。

用法1. 定义易于记忆的类型名:

   typedef 数据类型关键字 自定义类型名;

如: typedef float Dollars;

然后就可以直接用Dollars关键字来定义变量了,如:

Dollars cash_in, cash_out;   //它等同于float cash_in, cash_out;

上面是typedef的最简单的一个用法。

用法2. 定义一个指针类型的别名:

先看这行代码

char* pa, pb; // 声明了一个指向字符变量的指针,和一个字符变量,这多数不符合我们的意图

如果想定义两个都是指向字符变量的指针的,可利用typedef来实现:

typedef char* PCHAR;

PCHAR pa, pb;  

这种用法很有用,特别是char* pa, pb的定义,初学者往往认为是定义了两个字符型指针,其实不是,而用typedef char* PCHAR就不会出现这样的问题,减少了错误的发生。

 

用法3.  定义一个数组类型的别名

typedef    int   A[5];
定义了一个变量A的类型为一个含有5个元素的整型数组

"typedef    int   A[5]"中A是含有5个元素的数组类型的一个typedef-name。
下面两条语句:
A   a = {3, 4, 5, 7, 8};  /*正确*/
A   b = { 3, 4, 5, 7, 8, 9}; /* 会给出Warning: excess elements in array initializer */

用法4.  定义一个结构类型的别名

typedef   struct

{

     ... //

}  

Foo_t;
变量Foo_t的类型为struct { ... // } ;
=> "typedef   struct { ... // }   Foo_t "中Foo_t是"struct { ... // }"的一个typedef-name。这里struct {...//}是一个无"标志名称(tag name)"的结构体声明。

这种用法比较省事,尤其在大量使用的时候。

 

用法5. 为复杂的声明定义一个新的简单的别名

 

原声明:void (*b[10]) (void (*)());

变量名为b,先替换右边部分括号里的,pFunParam为别名一:

typedef void (*pFunParam)();

再替换左边的变量b,pFunx为别名二:

typedef void (*pFunx)(pFunParam);

原声明的最简化版:

pFunx b[10];

理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。

举例:

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。

 

 

用法6. 定义与平台无关的类型

例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以i获得最高的精度:

typedef long double REAL;

 

在不支持 long double 的机器上,该 typedef 看起来会是下面这样:

 

typedef double REAL;

并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:

typedef float REAL;

你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 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>>。


typedef的两个陷阱:

陷阱一:

可以象下面这样隐藏指针语法:

typedef char * pstr;
int mystrcmp(pstr, pstr);

这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个‘const char *’类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():

int mystrcmp(const pstr, const pstr);

这是错误的,按照顺序,‘const pstr’被解释为‘char * const’(一个指向 char 的常量指针),而不是‘const char *’(指向常量 char 的指针)。这个问题很容易解决:

typedef const char * cpstr;
int mystrcmp(cpstr, cpstr); // 现在是正确的

记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个 const,以使得该指针本身是常量,而不是对象。

陷阱二: 

typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; //不可行
编译将失败,会提示“指定了一个以上的存储类”。    

参考资料:

1.《C语言程序设计:现代方法》Page92, 93

2.  Using typedef to Curb Miscreant Code(URL:http://www.devx.com/cplus/10MinuteSolution/17527/1954?pf=true)

     使用 typedef 抑制劣质代码(URL: http://www.vckbase.com/document/viewdoc/?id=1365)

3.  也谈typedef(URL: http://bigwhite.blogbus.com/logs/20147715.html)

4.  关于typedef的用法总结(URL: http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值