content_views"
class="htmledit_views">
用途一:
定义一种类型的别名
c;而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; // 这多数不符合我们的意图
c;它只声明了一个指向字符变量的指针
c;
// 和一个字符变量;
以下则可行:
typedef
char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行
c;同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行
c;但相对来说没有用typedef的形式直观
c;尤其在需要大量指针的地方
c;typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查)
c;帮助
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct。以前的代码中
c;声明
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct新对象时
c;必须要带上
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct
c;即形式为:
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct 结构名 对象名
c;如:
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct tagPOINT1
{
int x;
int y;
};
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct tagPOINT1 p1;
而在C++中
c;则可以直接写:结构名 对象名
c;即:
tagPOINT1 p1;
估计某人觉得经常多写一个
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct太麻烦了
c;于是就发明了:
typedef
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; // 这样就比原来的方式少写了一个
class="tags" href="/tags/STRUCT.html" title=stru
ct>stru
ct
c;比较省事
c;尤其在大量使用的时候
或许
c;在C++中
c;typedef的这种用途二不是很大
c;但是理解了它
c;对掌握以前的旧代码还是有帮助的
c;毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与
class="tags" href="/tags/PingTai.html" title=平台>平台无关的类型。
比如定义一个叫 REAL 的浮点类型
c;在目标
class="tags" href="/tags/PingTai.html" title=平台>平台一上
c;让它表示最高精度的类型为:
typedef long double REAL;
在不支持 long double 的
class="tags" href="/tags/PingTai.html" title=平台>平台二上
c;改为:
typedef double REAL;
在连 double 都不支持的
class="tags" href="/tags/PingTai.html" title=平台>平台三上
c;改为:
typedef
class="tags" href="/tags/FLOAT.html" title=float>float REAL;
也就是说
c;当跨
class="tags" href="/tags/PingTai.html" title=平台>平台时
c;只要改下 typedef 本身就行
c;不用对其他源码做任何修改。
标准库就广泛使用了这个技巧
c;比如size_t。
另外
c;因为typedef是定义了一种类型的新别名
c;不是简单的字符串替换
c;所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明
c;如此循环
c;把带变量名的部分留到最后替换
c;得到的就是原声明的最简化版。举例:
1. 原声明:int *(*a[5])(int,
char*);
变量名为a
c;直接用一个新别名pFun替换a就可以了:
typedef int *(*pFun)(int,
char*);
原声明的最简化版:
pFun a[5];
2. 原声明:void (*b[10]) (void (*)());
变量名为b
c;先替换右边部分括号里的
c;pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b
c;pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
3. 原声明:doube(*)() (*e)[9];
变量名为e
c;先替换左边部分
c;pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e
c;pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起
c;先往右
c;再往左
c;碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号
c;还是按先右后左的顺序
c;如此循环
c;直到整个声明分析完。举例:
int (*fun
c)(int *p);
首先找到变量名fun
c
c;外面有一对圆括号
c;而且左边是一个*号
c;这说明fun
c是一个指针;然后跳出这个圆括号
c;先看右边
c;又遇到圆括号
c;这说明 (*fun
c)是一个函数
c;所以fun
c是一个指向这类函数的指针
c;即函数指针
c;这类函数具有int*类型的形参
c;返回值类型是int。
int (*fun
c[5])(int *);
fun
c右边是一个[]运算符
c;说明fun
c是具有5个元素的数组;fun
c的左边有一个*
c;说明fun
c的元素是指针(注意这里的*不是修饰fun
c
c; 而是修饰fun
c[5]的
c;原因是[]运算符优先级比*高
c;fun
c先跟[]结合)。跳出这个括号
c;看右边
c;又遇到圆括号
c;说明fun
c数组的元素是函数 类型的指针
c;它指向的函数具有int*类型的形参
c;返回值类型为int。
也可以记住2个模式:
type (*)(....)函数指针
type (*)[]数组指针
陷阱一:
记住
c;typedef是定义了一种类型的新别名
c;不同于宏
c;它不是简单的字符串替换。比如:
先定义:
typedef
char* PSTR;
然后:
int mystr
cmp(
const PSTR,
const PSTR);
const PSTR实际上相当于
const
char*吗?不是的
c;它实际上相当于
char*
const。
原因在于
const给予了整个指针本身以常量性
c;也就是形成了常量指针
char*
const。
简单来说
c;记住当
const和typedef一起出现时
c;typedef不会是简单的字符串替换就行。
陷阱二:
typedef在语法上是一个
class="tags" href="/tags/CunChu.html" title=存储>存储类的关键字(如auto、extern、mutable、stati
c、register等一样)
c;虽然它并不真正影响对象的
class="tags" href="/tags/CunChu.html" title=存储>存储特性
c;如:
typedef stati
c int INT2; //不可行
编译将失败
c;会提示“指定了一个以上的
class="tags" href="/tags/CunChu.html" title=存储>存储类”。