C++ typedef用法小结 (※不能不看※)

2023-05-16

第一、四个用途

用途一:

定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, 
// 和一个字符变量;
以下则可行:
typedef char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。

用途二:

用在旧的C的代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;

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

估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;

POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候

或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。

用途三:

用typedef来定义与平台无关的类型。
比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef long double REAL; 
在不支持 long double 的平台二上,改为:
typedef double REAL; 
在连 double 都不支持的平台三上,改为:
typedef float REAL; 
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。

用途四:

为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:

1. 原声明:int *(*a[5])(int, char*);
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int *(*pFun)(int, char*); 
原声明的最简化版:
pFun a[5];

2. 原声明:void (*b[10]) (void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];

3. 原声明:doube(*)() (*e)[9]; 
变量名为e,先替换左边部分,pFuny为别名一:
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。

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

第二、两大陷阱

陷阱一:

记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
先定义:
typedef char* PSTR;
然后:
int mystrcmp(const PSTR, const PSTR);

const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。

陷阱二:

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

以上资料出自:http://blog.sina.com.cn/s/blog_4826f7970100074k.html 作者:赤龙

第三、typedef 与 #define的区别

案例一:

通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

typedef char *pStr1;

#define pStr2 char *;

pStr1 s1, s2;

pStr2 s3, s4;

在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。

案例二:

下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

第四部分资料:使用 typedef 抑制劣质代码

作者:Danny Kalev
编译:MTT 工作室

原文出处:Using typedef to Curb Miscreant Code

摘要:Typedef 声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。不管怎样,使用 typedef 能为代码带来意想不到的好处,通过本文你可以学习用 typedef 避免缺欠,从而使代码更健壮。

typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。

Q:如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法?

A: 使用 typedefs 为现有类型创建同义字。

定义易于记忆的类型名
  typedef 使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于 ''typedef'' 关键字右边。例如:


typedef int size;  

此声明定义了一个 int 的同义字,名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size:


void measure(size * psz); size array[4];size len = file.getlength();std::vector <size> vs;   

typedef 还可以掩饰符合类型,如指针和数组。例如,你不用象下面这样重复定义有 81 个字符元素的数组:


char line[81];char text[81];  

定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:


typedef char Line[81]; Line text, secondline;getline(text);  

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


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 行为有点像 #define 宏,用其实际类型替代同义字。不同点是 typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。例如:


typedef int (*PF) (const char *, const char *);  

这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:


PF Register(PF pf);  

Register() 的参数是一个 PF 类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:


int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *);   

很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。持怀疑态度的人可能会问:“OK,有人还会写这样的代码吗?”,快速浏览一下揭示 signal()函数的头文件 <csinal>,一个有同样接口的函数。

typedef 和存储类关键字(storage class specifier)
  这种说法是不是有点令人惊讶,typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。下面将带到第二个陷阱:


typedef register int FAST_COUNTER; // 错误  

编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。

促进跨平台开发
  typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 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>>。

微软企业开发技术 | 移动开发(Google Android、Windows Mobile)技术| 嵌入式系统设计与开发 | JAVA开发
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ typedef用法小结 (※不能不看※) 的相关文章

  • Linux下搭建Git服务器

    目录 步骤一 安装Git xff1a 步骤二 服务器端创建git用户 xff08 管理Git服务 xff09 服务器端的Git配置公钥 生成rsa证书文件 步骤三 服务器端创建Git仓库 步骤四 客户端clone服务器端git仓库 1 在客
  • java -jar启动 报错: Error: Unable to access jarfile

    原因 xff1a 找不到jar包 xff0c 路径名称不对 xff1b 解决方案 xff1a 不要自己手动拼写输入jar包路径 xff0c 直接复制路径或tab键补齐
  • 买房子问题(break,continue,return的区别)

    问题描述 xff1a 蒜头君从现在开始工作 xff0c 年薪 NN 万 他希望在蒜厂附近买一套 6060 平米的房子 xff0c 现在价格是 200200 万 假设房子价格以每年百分之 KK 增长 xff0c 并且蒜头君未来年薪不变 xff
  • RabbitMQ 多实例 广播消息

    场景 xff1a 服务A发布消息 xff0c 要求多实例部署的服务B都要同时 接收到消息 问题 xff1a 第一反应想到是利用RabbitMQ的FANOUT Exchange把消息广播到绑定此exchange的队列上 此情况下多实例服务B肯
  • wget ftp 端口错误bad port spec

    span class token function wget span ftp ftpUser ftp span class token comment 123456 64 183 6 116 31 firmware update 1597
  • Spring Cloud Gateway配置HTTPS

    文章目录 1 阿里云申请免费证书2 购买证书3 配置域名4 下载证书5 配置网关ssl6 如果出现如下错误7 此时访问网关会报如下错误 8 配置tomcat 1 阿里云申请免费证书 登陆之后 xff0c 直接在产品和服务器中搜索 证书 2
  • spring security 自定义验证

    最近做项目遇到一个棘手的问题 项目是用spring security来控制权限的 这个框架有一套他自己的验证 xff0c 现在项目的要求是除了去数据库验证之外还要调用OA系统验证用户名和密码 就是在原来的基础上多加一层验证 而且密码不是要加
  • hibernate 执行本地sql 映射到实体类

    第一种方式 xff1a 1 全部映射 String sql 61 34 select c from 表名 c 34 SQLQuery navtiveSQL 61 this getCurrentSession createSQLQuery s
  • Spring 配置文件报错: cvc-elt.1: Cannot find the declaration of element ""beans""

    今天碰到一个奇怪的问题 xff0c spring在初始化xml配置文件的时候报错 xff1a Cannot find the declaration of element 39 beans 39 spring配置文件原来是这样写的 xff1
  • POJ 1201(差分约束+最长路)

    题意 xff1a 一个整数集合Z有n个区间 xff0c 每个区间有3个值 xff0c ai xff0c bi xff0c ci代表 xff0c 在区间 ai bi 上至少有ci个整数属于集合Z xff0c ci可以在区间内任意取不重复的点
  • JDK自带MD5加密算法

    其实jdk就自带了md5加密算法 xff0c 直接调用很方便 public static String md5 String source StringBuffer sb 61 new StringBuffer 32 try Message
  • 学习Flutter后对我的影响,阿里P6年薪40万+Flutter有这么大魅力-

    把 javascript 映射到原生 UI xff0c 使用原生 UI 的能力 这是 react native weex 采用的路线 Phone Gap 让人诟病的渲染性能让开发者思考一个问题 xff1a 如果 DOM 渲染效率太低 xff
  • linux禁用nouveau安装nvidia驱动遇到的问题

    1 禁用nouveau 安装nvidia显卡驱动首先需要禁用nouveau xff0c 不然会碰到冲突的问题 xff0c 导致无法安装nvidia显卡驱动 编辑文件blacklist conf sudo vim etc modprobe d
  • Linux第三次实验---进程管理

    文章目录 一 实验目的二 实验环境 xff1a 三 实验内容与步骤PART 1 进程基本操作PART 2 进程管理PART 3 定时执行命令PART 4 守护进程 一 实验目的 1 熟悉Linux操作系统环境 xff0c 掌握Linux命令
  • 如何设定Listview表头的背景色

    1 设定Listview的OwnerDraw属性为True 2 在Listview的DrawColumnHeader的事件中添加如下代码 xff1a e Graphics FillRectangle Brushes LightBlue e
  • DevExpress DataGrid Auto Filter Row 单元格实现单击全选

    如下图 xff0c 为提高工作效率 xff0c 要求单击时可以全选里面值 xff1a 研究了半天 xff0c 没有找到合适的事件 xff0c 后来还是在一个朋友的指点下得己实现 xff0c 代码如下 xff1a lt summary gt
  • MySQL 设定定时任务

    1 打开计划事件开关 SET GLOBAL event scheduler 61 ON 2 查看计划事件是否打开 SELECT 64 64 event scheduler 3 设定计划事件 CREATE EVENT IF NOT EXIST
  • MySQL 建视图时使用Union 报错1064

    SQL语句可以正常执行 xff0c 但创建视图时报错1064 xff0c 经多方资料查找 xff0c 格式调整 xff0c 原因竟然是不能用 xff08 xff09 xff0c 即创建视时SQL语句外围不能用 xff08 xff09 xff
  • C# winform ListView实现表示点击排序

    自用的小工具要实现这个功能 xff0c 网上找了些代码 xff0c 加工一下 xff0c 以下步骤 xff0c 亲测可用 菜鸟可一步步跟着来 xff0c 老鸟绕道啦 1 新建一个排序类 xff0c 代码如下 xff1a public cla
  • Oracle VM VirtualBox各种显示模式切换 热键

    初用VirtualBox 几个显示切换快捷键还是要记一下的 Right Ctrl 43 F 切换到全屏模式 Right Ctrl 43 L 切换到无缝模式 Right Ctrl 43 C 切换到比例模式 Right Ctrl 43 Home

随机推荐

  • PostgreSQL11.2 configure卡住 checking for DocBook XML V4.2

    在PG11 2的数据库编译过程中 xff0c 卡在了 checking for DocBook XML V4 2 xff0c 不动 xff0c 需要安装docbook才可以 需要安装 xff1a yum install docbook dt
  • 广东中山电信DNS地址 (铁通/网通)

    202 96 128 166 202 96 128 86 202 96 134 133 总忘 先记在这儿吧 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • SMARTFORM A5单据打印(自定义纸张/针式打印机)格式问题

    一张A5横放的单据 xff0c 做SmartForm时很自然的选择了DINA5 xff0c 然后横放 xff0c 测试的时候一直用激光打印机 xff0c 感觉挺正常 实际使用时发现异常 xff0c 不得己自己定义了一个A5横放的自定纸型 x
  • 检查c#代码内存泄露工具-CLR Profiler

    转自 xff1a http blog csdn net hualusiyu article details 8166450 大家都知道 net 有一套自己的内存 xff08 垃圾 xff09 回收机制 xff0c 除非有一些数据 xff08
  • 在SAP中创建并运用条形码

    原文地址 xff1a http blog chinaunix net u2 64924 showart 715473 html 在 SAP 中创建并运用条形码的过程如下 xff1a 1 以 T CODE xff1a SE73 进行后如图 x
  • 常用数据库建模工具

    收藏 xff1a http www oschina net project tag 83 db model Intellij下mybatis插件 MyBatisCodeHelper 国产 MyBatisCodeHelper 是 Intell
  • surface pro 4 发热抖屏的解决方法

    用了三年 xff0c 同样的问题 xff0c 以下方法试验中 以牺牲性能方法来降低发热 xff0c 从而避免抖屏 xff0c 不得已而为之 https tieba baidu com p 5598171696 red tag 61 1289
  • 关于物化视图增量刷新报ORA-12018 问题的解决方案

    由于表之前采用的是全量刷新方式进行刷新 xff0c 但是因为表的数据量越来越大 xff0c 全量刷新的时候偶尔会出现失败的情况 xff0c 因为同一个时点刷新的任务比较多 xff0c 回滚段被占满了之后会出现报错 xff0c 所以急需要解决
  • c语言中四种简单的数组排序

    前言 本文介绍了几种c语言中对乱序数组的排序方式 具体的内容有 xff1a 插入排序 xff1b 冒泡排序 xff1b 选择排序 xff1b 希尔排序 xff1b 具体内容详见下文 一 插入排序 1 思路 首先假设数组的的前n位元素是有序的
  • 网桥的功能和分类

    br lan 61 lan 网桥 将WLAN和LAN 交换机 绑定为一个虚拟接口 连接两个局域网 xff0c 负责数据的中继和转发 交换机的前生 集线器 xff08 Hub xff09 是中继器的一种形式 xff0c 区别在于集线器能够提供
  • Java简介

    今天开始学习Java啦 xff0c 每天进步一点点 xff01 1 Java语言发展史 Java语言是美国Sun Stanford University Network 公司在1995年推出的计算机语言 xff0c java之父 xff1a
  • win10上WSL+vscode+xserver配置linux图形化程序开发环境

    受够了双系统来回切换 xff0c 尝试了一下wsl配置linux环境 xff08 个人习惯在linux上敲代码 xff09 xff0c 由于需求图形化 xff0c 又弄了xserver 没有装linux图形界面 WSL 安装按着官方的文档来
  • 02.Ubuntu 18.04安装KVM

    02 Ubuntu 18 04安装KVM 1 检查是否支持虚拟化 span class token function egrep span span class token parameter variable c span span cl
  • maven 打包缺失 resources 目录下的 jar 包,警告 jar should not point at files within the project directory

    报错如下 INFO Scanning for projects WARNING WARNING Some problems were encountered while building the effective model for co
  • Linux 下利用trash替换rm

    前言 rmtrash 是linux和mac下命令行版本rm的回收站 xff0c 安装后对用户透明 xff0c 符合正常使用rm的习惯 支持rm fr file哦 xff0c 有了他再也不怕rm时候手颤抖了 能自动拒绝 rm fr 哦 安装
  • 【异常】记一次前端因资源无法加载导致白屏异常问题

    一 背景 自从运维同事强烈要求前端的环境要使用多套的 xff0c 参考文章 项目 参考若依的前端框架去多环境 于是一番捣鼓与改造之后 xff0c 看似已经顺利了 但运维说 xff0c 前端还是有问题 xff0c 需要他帮我改下 xff0c
  • 三种方法实现后入先出的栈---leetcode题解225

    声明 xff1a 问题描述来源于leetcode 一 问题描述 xff1a 用队列实现栈 CategoryDifficultyLikesDislikesalgorithmsEasy 67 64 480 Tags stack design C
  • iOS|开发小技巧之UIView创建xib

    我们有的时候在创建UIView的时候 xff0c 想要使用xib进行创建视图发现 xff0c xib文件不能和UIView文件一起创建 所以 xff0c 我们要单独创建xib文件 我们选择Empty文件 xff0c 而不要选择View文件
  • PyCharm中安装Vim插件ideavim 并关闭vim编辑模式

    在PyCharm中安装Vim插件ideavim 进入File菜单下的Settings下的Plugins 搜索ideaVim 找到ideaVim插件 点击Install安装 重启并享受在Pycharm环境中使用Vim的乐趣 支持Vim三种模式
  • C++ typedef用法小结 (※不能不看※)

    第一 四个用途 用途一 xff1a 定义一种类型的别名 xff0c 而不只是简单的宏替换 可以用作同时声明指针型的多个对象 比如 xff1a char pa pb 这多数不符合我们的意图 xff0c 它只声明了一个指向字符变量的指针 xff