详解typedef用法及define的区别

1.typedef语法描述

     在现实生活中,信息的概念可能是长度、数量和面积等。在C语言中,信息被抽象为int、float和double等基本数据类型。从基本数据类型名称上,不能看出其所代表的物理属性,并且int、float和double为系统关键字,不可以修改。为了解决用户自定义数据类型名称的需求,C 语言中引入typedef,可以为数据类型创建别名,从而丰富数据类型所包含的属性信息。

一般形式:

typedef  类型名称  类型别名

声明一个新的类型名的方法:

      1)  先按定义变量的方法写出定义体 ( 如:int i; )。

      2)  将变量名换成新的类型名 ( 将i换成COUNT )。

      3)  在最前面加typedef ( typedef int COUNT; )。

      4)  用新类型名去定义变量 ( COUNT num; )。

说明:

       1.typedef为系统关键字,“类型名称”为已知数据类型名称,包括基本数据类型(如char、int)、UDT(如数组、struct);

       2. typedef为数据类型创建别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。typedef是一种彻底的“封装”类型,在声明它之后就不能再往里面增加别的东西了。

       3.习惯上常把typedef声明的类型名用大写字母表示        

typedef double LENGTH;  
typedef unsigned int COUNT;
创建了别名之后,可像基本数据类型那样定义变量

例如:

typedef unsigned int COUNT;  
unsigned int b;  
COUNT c;

2.typedef主要应用形式

2.1为基本数据类型创建新类型名

例子:

typedef unsigned int COUNT;
typedef double AREA;
COUNT age;
AREA s;

应用的主要目的:

        首先是丰富数据类型中包含的属性信息,

        其次是为了系统移植的需要,稍后详细描述

2.2为UDT(结构体、公用体和枚举类型)创建简洁的类型名称

例子:

struct Point  
{  
double x;  
double y;  
double z;  
};  
struct Point oPoint1={100,100,0}; 
struct Point oPoint2;
      其中结构体 struct Point 为新的数据类型,在定义变量的时候均要有保留字struct,而不能像int和double那样直接使用Point来定义变量

如果经过如下的修改:

typedef struct tagPoint  
{  
 double x;  
 double y;  
 double z;  
} Point;  
使用typedef之后,定义变量简化为
Point oPoint;

2.3为数组创建简洁的类型名称

例如:

int a[10], b[10], c[10];
        在 C语言中,可以将长度为10的整型数组看作为一个 数据类型 ,再利用typedef为其重定义一个新 的名称,可以更加简洁形式定义此种类型的变量,具体的处理方式如下:
typedef int INT_ARRAY_10[10];  
typedef int INT_ARRAY_20[20];  

INT_ARRAY_10 a,b,c,d;  
INT_ARRAY_20 e;
       其中INT_ARRAY_10 和 INT_ARRAY_20为新的类型名,10和20 为数组的长度。a,b,c,d 均是长度 为 10 的整型数组,e 是长度为 20 的整型数组。

2.4为指针定义简洁的名称

        首先,为数据指针定义新的名称,在连续几个变量的声明中,用typedef定义的类型能够保证声明中的所有变量均为同一种类型如下:

typedef char * STRING;
STRING csName = “Jhon”;
其次,也可以为函数指针定义新的名称

typedef int (*MyFUN)(int a,int b);  

int Max(int a,int b);  

MyFUN pMyFun;  
pMyFun = Max; 
其中 MyFUN 代表  int XFunction(int a,intb)类型的函数指针的新名称。

3.typedef 的三个用途和两个陷阱 

  用途一

         定义一种类型的别名,而不只是简单的宏替换,可以用作同时声明指针型的多个对象。

typedef char * PCHAR;

PCHAR pa, pb;//同时声明了两个指向字符变量的指针
在大量使用指针的地方typedef更加方便

用途二

用 typedef 来定义与平台无关的类型。

typedef long double REAL; 

在不支持 long double 的平台二上,改为:    

typedef double REAL;  

       当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改,标准库就广泛使用了这个技巧,比如size_t。另外,因为 typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。

用途三

       为复杂的声明定义一个新的简单的别名,举例:

1. 原声明:int *(*a[5])(int, char*);

        变量名为 a,直接用一个新别名 pFun 替换 a 

typedef int *(*pFun)(int, char*); 

       原声明的最简化版:

pFun a[5]; 

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

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。

陷阱一

记住,typedef 是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。可以看作是一种彻底的“封装”

例子:

typedef char * PSTR;
#define DEFCHAR char*
  ....
char string[10] = "abcde";
 
const DEFCHAR p1 = string;//字符首地址
const PSTR p2 = string;

p1++; //ok
p2++; //error
printf("%c %c\n",*p1,*p2);

       通过编译运行可知:p2++出错。 

分析:     

     这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。

     上述代码中“第一个const”修饰的是“p1指向的对象,不能通过*p1改变对象的内容”;“第二个const”修饰的是“p2本身,p2是常量”const pStr p2并不等于const char * p2。const PSTR p2和const long x本质上没有区别,认为都是对变量进行只读限制;为了容易理解,可以把PSTR当作基本类型”来处理,只不过此处的基本类型是我们自己定义的而不是系统固有类型。因此,const PSTR p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

陷阱二

       typedef 在语法上是一个存储类的关键字(如 auto、extern、static、register),但它并不真正影响对象的存储特性,如:    

typedef static int INT2; //error,指定了一个以上的存储类  

3.typedef与define的区别

     1)#define是预处理指令,主要定义常量,此常量可以为任何的字符及其组合;在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:

#define PI 3.1415926

      程序中的:area=PI*r*r  会替换为 3.1415926*r*r ;如果你把#define 语句中的数字9写成字母g预处理也照样带入。

   2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名。

   3)#define在预处理时进行简单的替换,而 typedef不是简单替换 。例如:

#define int_ptr int *    
int_ptr a, b; //相当于int * a, b;只是简单的宏替换 
....
typedef int* int_ptr;    
int_ptr a, b; //a, b 都是指向int的指针,

   4)也许您已经注意到#define不是语句,不要在行末加分号,否则会连分号一块置换;而typedef是声明语句,有分号。




  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值