typedef的四个用途和两个陷阱

news/2024/7/5 19:28:46 标签: struct, 平台, 存储, 跨平台, float, c
cle class="baidu_pl">
cle_content" class="article_content clearfix">
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=struct>struct。以前的代码中࿰c;声明class="tags" href="/tags/STRUCT.html" title=struct>struct新对象时࿰c;必须要带上class="tags" href="/tags/STRUCT.html" title=struct>struct࿰c;即形式为:   class="tags" href="/tags/STRUCT.html" title=struct>struct   结构名   对象名࿰c;如:
class="tags" href="/tags/STRUCT.html" title=struct>struct   tagPOINT1
{
        int   x;
        int   y;
};
class="tags" href="/tags/STRUCT.html" title=struct>struct   tagPOINT1   p1;  

而在C++中࿰c;则可以直接写:结构名   对象名࿰c;即:
tagPOINT1   p1;

估计某人觉得经常多写一个class="tags" href="/tags/STRUCT.html" title=struct>struct太麻烦了࿰c;于是就发明了:
typedef   class="tags" href="/tags/STRUCT.html" title=struct>struct   tagPOINT
{
        int   x;
        int   y;
}POINT;

POINT   p1;   //   这样就比原来的方式少写了一个class="tags" href="/tags/STRUCT.html" title=struct>struct࿰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   (*func)(int   *p);
首先找到变量名funcc;外面有一对圆括号࿰c;而且左边是一个*号࿰c;这说明func是一个指针;然后跳出这个圆括号࿰c;先看右边࿰c;又遇到圆括号࿰c;这说明 (*func)是一个函数࿰c;所以func是一个指向这类函数的指针࿰c;即函数指针࿰c;这类函数具有int*类型的形参࿰c;返回值类型是int。
int   (*func[5])(int   *);
func右边是一个[]运算符࿰c;说明func是具有5个元素的数组;func的左边有一个*࿰c;说明func的元素是指针(注意这里的*不是修饰funcc; 而是修饰func[5]的࿰c;原因是[]运算符优先级比*高࿰c;func先跟[]结合)。跳出这个括号࿰c;看右边࿰c;又遇到圆括号࿰c;说明func数组的元素是函数 类型的指针࿰c;它指向的函数具有int*类型的形参࿰c;返回值类型为int。

也可以记住2个模式:
type   (*)(....)函数指针  
type   (*)[]数组指针  

陷阱一:
记住࿰c;typedef是定义了一种类型的新别名࿰c;不同于宏࿰c;它不是简单的字符串替换。比如:
先定义:
typedef   char*   PSTR;
然后:
int   mystrcmp(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、static、register等一样)࿰c;虽然它并不真正影响对象的class="tags" href="/tags/CunChu.html" title=存储>存储特性࿰c;如:
typedef   static   int   INT2;   //不可行
编译将失败࿰c;会提示“指定了一个以上的class="tags" href="/tags/CunChu.html" title=存储>存储类”。
cle>

http://www.niftyadmin.cn/n/1139154.html

相关文章

权威dns服务器存储信息,权威域名服务器

权威域名服务器 内容精选换一换本帖最后由知足常乐于2017-11-2513:02编辑DNS的查询过程有两种类型:递归查询和迭代查询。递归查询用于主机向本地域名服务器的查询。主机向本地域名服务器发出请求时,如果本地域名无法给出查询域名的IP地址,那么…

wps底纹去不掉_OMG | 没有它,娜扎徐璐脸上的痘也去不掉

如果没有好的皮肤底子,又怎么敢画裸妆呢?娜扎一直以来就以高颜值,好皮肤而出圈,让同是90后的妹子的我一直是又酸又羡慕。这几年皮肤状态越来越好,高清镜头下的皮肤也看不出什么瑕疵,肤质更是清透光亮&#…

新浪服务器远程安装系统,搭建PXE远程安装服务器+实现Kickstart无人值守安装

(基于vsftpd提供YUM软件仓库,基于PXE方式实现网络安装,基于kickstart配置文件实现自动应答。)系统环境(本实验为RHEL6虚拟机环境操作)软件环境:vsftpd-2.2.2-6.el6_0.1.i686sysstat-9.0.4-18.el6.i686dhcp-4.1.1-19.P1.el6.i686tftp-server-0…

Xerces C++解析XML文档

前一阵子学习Xerces-C++用于解析指定格式XML文档。在这里,把自己的学习经历和大家分享一下,在这里仅仅讲一些入门的知识,希望对大家有所帮助。 Xerces-C是什么? Xerces-C 的前身是 IBM 的 XML4C …

jenkins使用_使用Jenkins来发布和代理.NetCore项目

Back toStudy!注:书接上文,上回《【CI/CD系列】使用Docker安装Jenkins》咱们说到了使用Docker镜像的方式,来建立Jenkins服务,用来持续集成和持续发布项目,但是上一篇文章有两个问题:01创建的容器不能操作和…

浅谈C/C++内存泄露及其检测工具

http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c程序员来说,内存泄漏是一个常见的也是令人头疼的问题。已经有 许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等。Smart Pointer技术…

python编写一个模拟运算的程序_Python在Blender引擎中的动态模拟应用研究

龙源期刊网 http://www.qikan.com.cn Python 在 Blender 引擎中的动态模拟应用研 究 作者:郝振华 来源:《软件导刊》 2012 年第 11 期 摘 要:综合了 Blender 三维引擎的优点与重力加速算法建立了一个动态模拟应用的例子。 主要贡献在于&#…

C++面试题(附答案)

1.是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态? virtual修饰符会被隐形继承的。private 也被集成,只事派生类没有访问权限而已。virtual可加可不加。子类的空间里有父类的所有变量(static除外)。同一个函数只…