typedef和#define的用法与区别

2023-11-12

typedef和#define的用法与区别

 

一、typedef的用法

在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像:

typedef    int       INT;
typedef    int       ARRAY[10];
typedef   (int*)   pINT;

typedef可以增强程序的可读性,以及标识符的灵活性,但它也有“非直观性”等缺点。

 

二、#define的用法

#define为一宏定义语句,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它本身并不在编

译过程中进行,而是在这之前(预处理过程)就已经完成了,但也因此难以发现潜在的错误及其它代码维护问题,它的实例像:

#define   INT             int
#define   TRUE         1
#define   Add(a,b)     ((a)+(b));
#define   Loop_10    for (int i=0; i<10; i++)

在Scott Meyer的Effective C++一书的条款1中有关于#define语句弊端的分析,以及好的替代方法,大家可参看。

 

三、typedef与#define的区别

从以上的概念便也能基本清楚,typedef只是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),而#define原本在C中是为了定义常量

,到了C++,const、enum、inline的出现使它也渐渐成为了起别名的工具。有时很容易搞不清楚与typedef两者到底该用哪个好,如#define

INT int这样的语句,用typedef一样可以完成,用哪个好呢?我主张用typedef,因为在早期的许多C编译器中这条语句是非法的,只是现今的

编译器又做了扩充。为了尽可能地兼容,一般都遵循#define定义“可读”的常量以及一些宏语句的任务,而typedef则常用来定义关键字、冗

长的类型的别名。

宏定义只是简单的字符串代换(原地扩展),而typedef则不是原地扩展,它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变

量的功能。请看上面第一大点代码的第三行:

typedef    (int*)      pINT;
以及下面这行:
#define    pINT2    int*

效果相同?实则不同!实践中见差别:pINT a,b;的效果同int *a; int *b;表示定义了两个整型指针变量。而pINT2 a,b;的效果同int *a, b;

表示定义了一个整型指针变量a和整型变量b。

 

 

 

typedef的四个用途和两个陷阱

用途一: 
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如: 
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;   //不可行 
编译将失败,会提示“指定了一个以上的存储类”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

typedef和#define的用法与区别 的相关文章

  • 北大igem生物计算机,喜讯|北京大学iGEM团队在国际大赛中取得金牌

    原标题 喜讯 北京大学iGEM团队在国际大赛中取得金牌 美国东部时间2017年11月13日下午 在波士顿Hynes会议中心举办的国际基因工程机器大赛 International Genetically Engineered Machine
  • YOLO 算法系列

    我们分享了YOLO系列的文章 包括前段时间刚刚发布的YOLOv7检测算法 虽然YOLOv7对象检测算法是YOLO最新的模型 且可以支持对象分割 人体姿态检测等 但是最新的YOLO系列检测模型也同步进行了更新 那就是刚刚开源的YOLOv8对象
  • 在Ubuntu20.10中搭建TFTP服务器

    TFTP Trivial File Transfer Protocol 是用来下载远程文件的最简单的网络协议 它基于UDP协议而实现 一 安装 sudo apt get install tftp hpa tftpd hpa tftp hpa
  • Apache Hive基础

    Apache Hive基础 Hive优势 提供了一个简单的优化模型 HQL类SQL语法 简化MR开发 支持在不同的计算框架上运行 支持在HDFS和HBase上临时查询数据 支持用户自定义函数 格式 成熟的JDBC和ODBC驱动程序 用于ET
  • matlab如何预测数据,matlab预测数据

    基于MATLAB 的人口预测模型 摘要 本文以 1980 2014 年中国年终总人口数据资料为依据 分别使用了一次拟合 灰色预 测模型和时间序列模型进行拟合 最终得出时间序列模型 基于MATLAB 的人口预测方法分析 易亮 摘要 摘要 本文
  • Android Looper Handler 机制浅析

    最近想写个播放器demo 里面要用到 Looper Handler 看了很多资料都没能理解透彻 于是决定自己看看相关的源码 并在此记录心得体会 希望能够帮助到有需要的人 本文会以 猜想 log验证 的方式来学习 Android Looper
  • java 执行bat文件

    Java代码 cmd c dir 是执行完dir命令后关闭命令窗口 RequestMapping a ResponseBody public Object a String command cmd c D Users qwer Deskto
  • 基于51单片机的自动浇花浇水系统LCD1602显示仿真

    硬件设计 基本框架 该电路的工作原理是由STC89C52单片机和ADC0832组成系统的核心部分 湿度传感器将采集到的数据直接传送到ADC0832的IN端作为输入的模拟信号 选用湿度传感器和AD转换 电路内部包含有湿度采集 AD转换 单片机
  • 7-3 谁是赢家

    7 3 谁是赢家 某电视台的娱乐节目有个表演评审环节 每次安排两位艺人表演 他们的胜负由观众投票和 3 名评委投票两部分共同决定 规则为 如果一位艺人的观众票数高 且得到至少 1 名评委的认可 该艺人就胜出 或艺人的观众票数低 但得到全部评
  • vue 图片,视频点击预览按钮方法

    图片 使用el image viewer组件 写之前注意引入安装组件 主要代码 div class div
  • opencv之初学第3天

    opencv学习第三天 今天学习一下灰度变换 我对图像不是太了解 我还特地学了一下灰度变换与像素的区别 像素 灰度 RGB 分辨率 y xxiii的博客 CSDN博客 像素值和rgb的关系 先来梳理一下不太懂的知识点 1 关于cvtColo
  • Windows下安装zerotier,网络状态提示PORT_ERROR错误解决

    ZeroTier是一款基于P2P的内网穿透工具 支持多客户端 手机电脑可以互通互联 最近为方便nas操作 在电脑上部署安装 结果踩坑 在Windows下使用zerotier时提示PORT ERROR错误 最初以为是端口被屏蔽 关闭防火墙 发
  • 【转】DevOps的前世今生

    目前在国外 互联网巨头如Google Facebook Amazon LinkedIn Netflix Airbnb 传统软件公司如Adobe IBM Microsoft SAP等 亦或是网络业务非核心企业如苹果 沃尔玛 索尼影视娱乐 星巴
  • [bx]和loop指令

    1 bx 的含义 bx 表示一个内存单元 它的偏移地址在bx中 比如 mov ax bx 会将一个内存单元的内容送入ax 这个内存单元的长度是2个字节 存放一个字 偏移地址存放在bx中 段地址在ds中 mov al bx 则是移动半个字 2
  • openGL API glDeleteSamplers中文翻译

    openGL API glDeleteSamplers中文翻译 先放上英文 后面是中文翻译 Name glDeleteSamplers delete named sampler objects C Specification void gl

随机推荐

  • windows server 2003 永恒之蓝(MS17-010)漏洞复现

    目录 永恒之蓝 概述 防护方式 复现 复现工具 复现过程 侦测部分 用于侦测靶机是否具有ms17 010漏洞 攻击部分 永恒之蓝 概述 永恒之蓝是指2017年4月14日晚 黑客团体Shadow Brokers 影子经纪人 公布一大批网络攻击
  • ImportError: cannot import name 'json_util' from 'bson'

    最近使用bson的json util时出现错误 错误提示如下 ImportError cannot import name json util from bson OR ImportError No module named bson js
  • 面试总结(JavaWeb后端工程师三年面试问题,附答案!)

    笔者在今年上半年辞职了 陆陆续续面试了一些互联网公司 一起来看看这些公司都问的些什么面试题吧 一 Spring MVC和Spring boot有啥区别 1 Spring MVC和Spring Boot都是Spring的一部分 且两者都是由I
  • 刷脸支付条赛道上支付宝遥遥领先

    社会经济在快速发展 而身边所携带的现金却在慢慢减少 很多人甚至出门都不带现金 尤其是早晨着急上班的时候 在地铁口附近买包子需要付款时 手中无现金 拿出手机又嫌麻烦 刷脸似乎更为便捷 于是乎 脸就变得越来越值钱 靠脸吃饭不再仅仅局限于偶像明星
  • 【jar包】java -jar 启动服务,断开服务器连接或者关闭窗口后,服务停止

    解决办法 nohup java jar XXX jar gt log file 最后的 在后台运行 只能避免打断后程序停止 无法避免关闭当前窗口 最前面的nohup 不挂断运行命令 当账户退出或终端关闭时 程序仍然运行 输出到log fil
  • 服装行业多模态算法个性化产品定制方案

    一 项目背景 AI赋能服装设计师 设计好看 好穿 好卖的服装 传统服装行业痛点 设计师无法准确捕捉市场趋势 抓住中国潮流 上新周期长 高库存滞销风险大 基本款居多 难以满足消费者个性化需求 解决方案 GPT 数据洞察 快速反应市场时尚流行趋
  • pycharm安装2021最新详细教程小白入门

    一 官网下载安装包 Pycharm的官网 https www python org 这个链接进去直接是下载界面 https www jetbrains com pycharm download 1 专业版 Professional 是收费的
  • C++基本语法

    C 中构造函数的调用 class Type void main Type obj ok 编译器调用了默认的构造函数 Type obj1 Type ok 显示调用了默认的构造函数 Type obj3 error 其是声明了一个无参并返回Typ
  • 控制台get的两种提交方式

    本次学习需要打开Visual Studio 2015简称 VS 开发工具 其他的版本也可以使用 打开进入页面创建项目 创建的项目命名为控制台get提交的两种方式 之后我们在软件默认的位置 保存的位置可以进行更改 之后就到更改的位置中查找 中
  • axios 请求自动携带 cookie

    axios 请求自动携带 cookie axios默认是不让ajax请求头部携带cookie的 添加withCredentials设置 const instance axios create baseURL http 127 0 0 1 3
  • Java 实现暴力匹配算法(也称为朴素字符串匹配算法)

    摘要 暴力匹配算法 也称为朴素字符串匹配算法 是一种简单但有效的字符串匹配算法 它通过遍历主串和模式串的每一个字符 并在遇到不匹配的情况下逐个后移字符进行匹配 本文将使用Java语言实现暴力匹配算法 并对其性能进行简要分析 介绍 字符串匹配
  • C 简介

    原文链接 https www runoob com cprogramming c intro html C 语言是一种通用的高级语言 最初是由丹尼斯 里奇在贝尔实验室为开发 UNIX 操作系统而设计的 C 语言最开始是于 1972 年在 D
  • 每日一问—03如何拆分指定页码pdf

    一 各页码范围合成一个整体的pdf import PyPDF2 导入PyPDF2模块 def merge pdf pages input pdf page ranges output pdf reader PyPDF2 PdfFileRea
  • 越来越智能的云,如何助力实体经济?

    2023 年腾讯全球数字生态大会即将举行 每一年的大会 腾讯都会带来新的思考和实践 今年也不例外 今年 大会的主题是 智变加速 产业焕新 意即数字经济正发生的变化 以大语言模型为代表的人工智能 正在带来全新的科技变革 如何为实体经济创造新的
  • 西门子PLC通信全解析

    前言 最近西门子PLC价格大幅上调 在工控界引起了不小的风波 不仅涨价 甚至还缺货 导致很多人不得不更改方案 听说最近已经完成了芯片替换 希望不久能够恢复供货 并把价格回调 通过这件事 从侧面可以看出 西门子在工控领域的市场占有率很大 那么
  • Oracle date(时间)类型详解

    常用日期型数据类型 TIMESTAMP类型是DATE类型的一个扩展 DATE类型会存储年月日时分秒信息 TIMESTAMP类型精度更高 会存储到微秒 纳秒 1 DATE 展示格式既可以为 YYYY MM DD 也可以为YYYY MM DD
  • 数据分析课程笔记(二)绘制散点、条形、直方图 Numpy简介

    数据分析课程笔记 绘制散点图 绘制条形图 绘制横着的条形图 例子 绘制直方图 直方图更多场景 常见问题总结 matplotlib使用流程 matplotlib更多的图形样式 更多绘图工具 numpy numpy创建数组 矩阵 numpy中常
  • Adams——SolidWorks模型导入到Adams中

    1 SOLIDWORKS模型转入ADAMS的格式及导入步骤 首先将零件图或者装配图另存为 parasolid格式 其次将保存好的 parasolid格式文件的后缀改为 xmt txt 之所以这样做可以避免模型中多个实体的重复 注意保存路径不
  • 【经验分享】让iPad或者手机作为电脑扩展屏幕使用—Splashtop Wired XDisplay(亲测有效且免费)

    最近 由于疫情的影响只能进行居家隔离办公 平时习惯使用双屏幕 在家一台笔记本操作有点不适应 由此想到拿手里的ipad实现电脑扩展屏 网上看了有很多可以实现 iPad 如何实现电脑屏幕扩展 有 Duet Display TwomonUSB s
  • typedef和#define的用法与区别

    typedef和 define的用法与区别 一 typedef的用法 在C C 语言中 typedef常用来定义一个标识符及关键字的别名 它是语言编译过程的一部分 但它并不实际分配内存空间 实例像 typedef int INT typed