typedef 的用法总结

本文详细介绍了typedef在C语言中的用法,包括为类型起别名、定义数组类型、结构体和枚举类型数据。typedef不仅可以简化代码,还可以在跨平台时提供便利,与#define不同,它在编译时解析,保证了类型安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、typedef   用于为原有的类型名起新的容易记住的名字,定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:

typedef int size;
typedef unsigned int WORD;


第一个声明定义了一个char的同义词,名字为C,你可以在任何需要int的上下文使用size。
第二个声明定义了一个unsigned int的同义词,名字为WORD,你可以在任何需要int的上下文使用WORD。

char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,

// 和一个字符变量;

以下则可行:

typedef char* PCHAR;

PCHAR pa, pb;  

这种用法很有用,特别是char* pa, pb的定义,初学者往往认为是定义了两个字符型指针,其实不是

2、

typedef   用于定义数组类型和指针类型

 一维数组类型的定义格式
        typedef <元素类型关键字><数组类型名>[<常量表达式>];
    例如:
    (1) typedef int vector[10];
    (2) typedef char strings[80];
    (3) typedef short int array[N];

第一条语句定义了一个元素类型为int,含有10个元素的数组类型vector,若不使用typedef保留字,则就变成了数组定义,它只定义了一个元素类型为int、含有10个元素的数组vector。这两种定义有着本质的区别,若定义的是数组vector,系统将为它分配有保存10个整数的存储单元,共40个字节的存储空间;若定义的是数组类型vector,系统只是把该类型的有关信息登记下来,待以后利用该类型定义对象时使用,具体地说,就是把vector的元素类型int,类型长度10,类型名vectoe等登记下来,待以后定义vector类型的对象时使用。例如:

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

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

typedef char Line[81]; 
Line text, secondline;
类似的指针的用法也类似:
typedef char * pstr; 
pstr str = "abc";
int mystrcmp(pstr, pstr);


3、

typedef   用于函数指针

 typedef 行为有点像 #define 宏,用其实际类型替代同义字。

 不同点:typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换

用法一:

typedef int (*MYFUN)(int, int)
这种用法一般用在给函数定义别名的时候
上面的例子定义MYFUN 是一个函数指针, 函数类型是带两个int 参数, 返回一个int 

分析这种形式的定义的时候可以用下面的方法: 
先去掉typedef 和别名剩下的就是原变量的类型. 
去掉typedef和MYFUN以后就剩:
 
int (*)(int, int)

void printHello(int i);

然后我们要定义一个函数指针,指向printHello,并且调用这个方法,代码如下:

void (*pFunc)(int);
pFunc = &printHello;
(*pFunc)(110);

其中void (*pFunc)(int)是声明一个函数指针,指向返回值是void,调用参数是(int)的函数,变量名是pFunc,pFunc就是函数指针了,以前是函数指针的简单用法。
大家可以看到,声明一个函数指针是比较复杂的,尤其是当你要在多处地方声明同一个类型的函数指针变量,代码更加复杂,所以有下面简化的做法:

typedef void (*PrintHelloHandle)(int);

使用代码如下:

PrintHelloHandle pFunc;
pFunc = &printHello;
(*pFunc)(110);

以后其他地方的程序需要声明类似的函数指针,只需要下面代码:

PrintHelloHandle pFuncOther;

理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号

就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直

到整个声明分析完。举例:

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。

我们要从指针的层次上理解函数-函数的函数名实际上就是一个指针函数名指向该函数的代码在内存中的首地址

//#include<iostream.h>   
#include<stdio.h>   
  
typedef int (*FP_CALC)(int, int);   
//注意这里不是函数声明而是函数定义,它是一个地址,你可以直接输出add看看   
int add(int a, int b)   
{   
     return a + b;   
}   
int sub(int a, int b)   
{   
     return a - b;   
}   
int mul(int a, int b)   
{   
     return a * b;   
}   
int div(int a, int b)   
{   
     return b? a/b : -1;   
}   
//定义一个函数,参数为op,返回一个指针。该指针类型为 拥有两个int参数、   
//返回类型为int 的函数指针。它的作用是根据操作符返回相应函数的地址   
FP_CALC calc_func(char op)   
{   
     switch (op)   
      {   
     case '+': return add;//返回函数的地址   
     case '-': return sub;   
     case '*': return mul;   
     case '/': return div;   
     default:   
         return NULL;   
      }   
     return NULL;   
}   
//s_calc_func为函数,它的参数是 op,   
//返回值为一个拥有 两个int参数、返回类型为int 的函数指针   
int (*s_calc_func(char op)) (int, int)   
{   
     return calc_func(op);   
}   
//最终用户直接调用的函数,该函数接收两个int整数,和一个算术运算符,返回两数的运算结果   
int calc(int a, int b, char op)   
{   
      FP_CALC fp = calc_func(op); //根据预算符得到各种运算的函数的地址   
         int (*s_fp)(int, int) = s_calc_func(op);//用于测试   
         // ASSERT(fp == s_fp);    // 可以断言这俩是相等的   
     if (fp) return fp(a, b);//根据上一步得到的函数的地址调用相应函数,并返回结果   
     else return -1;   
}   
  
void main()   
{      
    int a = 100, b = 20;   
  
      printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));   
      printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));   
      printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));   
      printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));   
}  
4、

typedef   用于结构体

ypedef给变量类型定义一个别名.

typedef struct{ 
int a; 
int b; 
}MY_TYPE

这里把一个未命名结构直接取了一个叫MY_TYPE的别名, 这样如果你想定义结构的实例的时候就可以这样: 
MY_TYPE tmp;

5、

typedef   用于枚举类型数据

typedef enum workday
{
    saturday,
    sunday 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
workday; //
此处的workday为枚举型enum workday的别名

 

workday today, tomorrow; //变量todaytomorrow的类型为枚举型workday,即enum workday

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

比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

typedef long double REAL;

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

typedef double REAL;

在连 double 都不支持的平台三上,改为:

typedef float REAL;

也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

标准库就广泛使用了这个技巧,比如size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。

7

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++错误。P2++确实不可以,编译出错。因为P2是常量,不能修改其指向。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值