typedef详解以及与宏定义#define的区别

typedef是在计算机编程语言中用来为复杂的声明定义简单的别名,它与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中;
typedef 中文解释:声明类型

typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)

在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

主要用法:
1、创建平台无关的数据类型,隐藏笨拙且难以理解的语法

typedef int size;
void measure(size*psz);
size array[4];

已知数据类型long起个新名字byte_4

typedef long byte_4;

2、掩饰复合类型,如指针和数组
下面这样重复定义有 81 个字符元素的数组:

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

定义,Line类型即代表了具有81个元素的字符数组,使用方法如下:

typedef char Line[81];
Line text,line;

typedef int array[2];

array等价于 int [2]定义;
array a声明等价于int a[2]声明

typedef int array[M][N];

array等价于 int [M][N]定义;
array a声明等价于int a[M][N]声明

隐藏指针语法:

typedef char* pstr;
int mystrcmp(const pstr p1,const pstr p3);

eg:

  typedef int *pointer;

pointer等价于 int *定义;
pointer p声明等价于int *p声明

eg:

 typedef int *pointer[M];

pointer等价于 int *[M]定义;
pointer p声明等价于int *p[M]声明

3、typedef与结构结合使用

typedef struct tagMyStruct
{
	int iNum;
	long lLength;
}MyStruct;

这语句实际上完成两个操作:
(1)定义一个新的结构类型

struct tagMyStruct
{
	int iNum;
 	long lLength;
};

tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。
(2)typedef为这个新的结构起了一个名字,叫MyStruct。

typedef struct tagMyStruct MyStruct;

因此,MyStruct实际上相当于struct tagMyStruct,可以使用MyStruct varName来定义变量。

4、下面的代码定义一个结构时,编译器报了一个错误,莫非C语言不允许在结构中包含指向它自己的指针吗?

typedef struct tagNode
{
	char* pItem;
	pNode* pNext;
}pNode;

分析:
C语言当然允许在结构中包含指向它自己的指针,上述代码的根本问题在于typedef的应用。新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。
解决这个问题的方法有多种:
(1)

typedef struct tagNode
{
	char* pItem;
	struct tagNode* pNext; 
}*pNode;

(2)

typedef struct tagNode* pNode;
struct tagNode
{
	char* pItem;
	pNode pNext;//这边不用pNode* ,pNode 已经表示了struct tagNode*
};

注意:在这个例子中,typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法,但是不推荐这种写法。
(3)

struct tagNode
{
	char* pItem;
	struct tagNode* pNext;
};
typedef struct tagNode* pNode;

5、函数声明

 typedef int func(void);

func等价于 int (void)类型函数;
func f声明等价于 int f(void)声明,用于文件的函数声明;
func *pf声明等价于 int (*pf)(void)声明,用于函数指针;

6、函数指针

 typedef int (*func)(void)

func等价于int (*)(void)类型;
func pf等价于int (*pf)(void)声明,pf是一个函数指针变量

7、 typedef & #define的区别
在这里插入图片描述
#define只是简单的字符串替换而typedef则是为一个类型起新名字。
一般来说,typedef要比#define要好,特别是在有指针的场合。

typedef char* pStr1;
#define pStr2 char* 
pStr1 s1,s2;
pStr2 s3,s4;

在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是所预期的指针变量。要达到所预期的效果,上例中define语句必须写成 pStr2 s3, *s4; 这样才能正常执行。

8、#define用法陷阱

#include <stdio.h>
#define f(x) x*x
int main(void)
{
    int a=6, b=2, c;
    c = f(a) / f(b);
    printf("%d\n", c);
    return 0;
}

程序的输出结果是: 66/22=36,并不是预期的(66)/(22)=9;
如此原因,在许多C语言编程规范中提到 使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:

#definef(x)((x)*(x))

9、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和pStr const p2本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此 const pStr p2的含义是,限定数据类型为char *的变量p2为只读 ,因此p2++错误。

10、 #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。

在C或C++语言中,“宏”分为有参数和无参数两种。
(1)无参宏的宏名后不带参数。

#define 标识符 字符串

其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。

#define M (a+b)

注意:宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令

(2)c语言允许宏带有参数。
在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

#define 宏名(形参表) 字符串
#define M(y) ((y)*(y)+3*(y)) /*宏定义*/
....
k=M(5); /*宏调用*/
....

在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:
k=5*5+3*5

(3)防止重复定义

#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件内容
…
#endif

(4)简单定义

#define MAXTIME 1000

(5)条件编译-1

#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
#endif

(6)条件编译-2

#ifdef XXX…(#else) … #endif

eg:

#ifdef AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif

11、 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()函数的头文件 ,一个有同样接口的函数。

注意这里Register被定义为一个函数而不是函数指针,如果要定义为函数指针应该这样写:

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

12、ypedef 另外一个重要的用途,那就是定义机器无关的类型
定义一个叫 REAL 的浮点类型,在目标机器上它可以获得最高的精度:

typedef long double REAL;

在不支持 long double 的机器上,该 typedef 看起来会是下面这样:

typedef double REAL;

并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:

typedef float REAL;

你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 REAL 类型的应用程序。
唯一要改的是 typedef 本身。
标准库广泛地使用 typedef 来创建这样的平台无关类型

13、结构体有无typedef的区别

struct node{
	datatype data;
	struct node *lchild,*rchild;
}bintnode;

上述代码相当于:

struct node{
	datatype data;
	struct node *lchild,*rchild;
};
struct node bintnode;

一个类型struct node的完整描述,并定义了一个struct node类型的对象bintnode。

typedef struct node{
	datatype data;
	struct node *lchild,*rchild;
}bintnode;

上述代码相当于:

 struct node{
	 datatype data;
	 struct node *lchild,*rchild;
    };
  typedef  struct node   bintnode;

定义了一个类型别名bitnode,实际上指的就是struct node这个完整类型.typedef定义的类型别名在作用域内和被定义的原类型语义上等价,都是表示同一个类型的名称。这里typedef之后bitnode可以和struct node互相代替。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`typedef` 和宏定义是 C 语言中用于创建别名和定义常量的两种不同机制。 `typedef` 是一个关键字,它用于为已有的数据类型创建新的别名。通过 `typedef`,您可以为某个数据类型定义一个新的名称,以便在程序中使用更加直观和可读的标识符。下面是 `typedef` 的语法: ```c typedef 已有的数据类型 新的数据类型名称; ``` 例如,我们可以使用 `typedef` 为 `int` 类型创建一个新的名称 `MyInt`: ```c typedef int MyInt; ``` 现在,`MyInt` 就成为了 `int` 类型的别名,在程序中可以直接使用 `MyInt` 来代替 `int`。 宏定义则是一种用预处理器指令定义常量或创建代码片段的机制。通过宏定义,您可以为某个值或代码片段定义一个符号常量或缩写,并在程序中多次使用。下面是宏定义的语法: ```c #define 名称 值或代码片段 ``` 例如,我们可以使用宏定义创建一个常量 `PI`: ```c #define PI 3.14159 ``` 在程序中使用时,预处理器会将 `PI` 替换为对应的值。 同时,宏定义也可以用于创建带参数的代码片段,类似于宏定义函数。例如: ```c #define SQUARE(x) ((x) * (x)) ``` 在程序中使用 `SQUARE` 时,预处理器会将调用替换为相应的代码。 需要注意的是,宏定义是在预处理阶段进行替换的,而 `typedef` 是在编译阶段进行处理的。宏定义没有类型检查,而 `typedef` 创建的别名具有原始类型的属性和限制。因此,在使用宏定义时需要格外小心,避免潜在的问题。而 `typedef` 则更加安全可靠,推荐在需要为已有类型创建别名时使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT技术猿猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值