typedef是一种有趣的声明形式:它为一种类型引入新的名字,而不是为变量分配空间。在某些方面,typedef类似于宏文本替换——它并没有引入新的类型,而是为现有类型取个新名字,但它们之间存在一个关键性的区别。

typedef关键字可以是一个常规声明的一部分,可以出现在靠近声明开始部分的任何地方。事实上,typedef 的格式与变量声明完全一样,只是多了这个关键字,向你提醒它的实质。由于typedef看上去跟变量声明完全一样,它们读起来也是一样的。普通的声明表示“这个名字是一个指定类型的变量”,而typedef关键字并不是创建一个变量,而是宣称“这个名字是指定类型的同义词”。

一般情况下,typedef用于简洁的表示指向其他东西的指针。典型的例子是signal()原型的声明。signal()是一种系统调用,用于通知运行时系统:当某种特定的“软件中断”发生时调用特定的程序。调用signal()并通过传参告诉它中断的类型以及用于处理中断的程序。在ANSI C标准中,signal()的声明如下:

void (*signal(int sig,void(*func)(int)))(int);

用分析C语言的声明(2)介绍的方法分析这个声明:

首先:

void (*signal( ))(int);

signal是一个函数,它返回一个函数指针,后者所指向的函数接受一个int参数并返回void。

其中提取出来的通用的部分是:

void (*func)(int);

这个表示一个函数指针,所指向的函数接受一个int参数,返回值是void。下面用typedef来“代表”通用部分,从而进行简化:

typedef void (*ptr_to_func) (int);

/* 它表示ptr_to_func是一个函数指针,该函数接受一个int参数,返回值为void。*/

ptr_to_func signal(int, ptr_to_func);

/* 它表示signal是一个函数,它接受两个参数,

其中一个是int,另一个是ptr_to_func,返回值是ptr_to_func。*/

然而,说到typedef就不能不说一下它的缺点。它同样具有其他声明一样的混乱语法,同样可以把几个声明器塞到一个声明中去。对于结构体,除了可以在书写时省掉struct关键字之外,typedef并不能提供显著的好处,而少些一个struct其实并没有多大帮助。在任何typedef声明中,甚至不必把typedef放在声明的开始位置。

typedef和#define的区别

typedef和define之间有一个关键性的区别。正确思考这个问题的方法就是把typedef看成是一种彻底的“封装”类型——在声明它之后不能再往里面增加别的东西。它和define的区别体现在两个方面:

1.可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。如下所示:

#define peach int

unsigned peach i ; //没有问题

typedef int banana;

unsigned banana i;//错误,非法

2.在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一种类型,而用#define定义的类型则无法保证。如下所示:

#define int_ptr int *

int_ptr chalk, cheese;

经过宏扩展,第二行变为:

int * chalk, cheese;

这使得chalk和cheese成为不同的类型:chalk是一个指向int的指针,而cheese则是一个int。

typedef char * char_ptr;

char_ptr Bentley, Rolls_Royce;

使用typedef定义的类型能够保证它们的类型相同,都是指向char的指针。

typedef struct foo{ ... foo;}的含义

C语言存在多种名字空间:

标签名(label name)。

标签(tag):这个名字空间用于所有的结构体、枚举和联合。

成员名:每个结构体或联合都有自身的名字空间。

其他。

在同一个名字空间里,任何名字必须具有唯一性,但在不同的名字空间里可以存在相同的名字。由于每个结构体或联合具有自己的名字空间,所以同一个名字可以出现在许多不同的结构内。有时可以看到这样的代码:

struct foo { int foo;} foo;

这显然会让将来维护这段代码的程序员感到困惑和沮丧,你说sizeof(foo)到底是表示哪个foo呢?

有些东西更加稀罕,像下面这样的声明竟然也是合法的:

typedef struct baz { int baz; } baz;

struct baz variable_1;

baz variable_2;

太多的“baz”了!让我们换一些清楚的名字,整理一下:

typedef struct my_tag { int i; } my_type;

struct my_tag variable_1;

my_type variable_2;

这个typedef声明引入了my_type这个名字作为"struct my_tag { int i; }"的简写形式。如果你用typedef声明一个标识符表示struct 结构类型,那么以后使用这个标识符时前面就不必加上关键字struct 了。但这个typedef声明同时也引入了结构标签my_tag,在它面前加个关键字struct可以表示同样的意思。

下面两个声明具有相似的形式:

typedef struct fruit { int weight , price_per_lb; } fruit; // 语句1

struct veg { int weight , price_per_lb; } veg; //语句2

但它们代表的意思却完全不一样,语句1声明了结构体标签”fruit“和由typedef声明的结构体类型”fruit“,其实际效果如下:

struct fruit mandarin; //使用结构体标签”fruit“

fruit mandarin; //使用结构体类型”fruit“

语句2声明了结构体标签”veg“和变量veg。只有结构体标签能够在以后的声明中使用,如:

struct veg potato;

如果试图使用veg cabbage这样的声明,将是一个错误。

使用typedef的一些提示:

1.不要在一个typedef中放入几个声明器,如下所示:

typedef int *ptr, (fun()), arr[5];

/* ptr是“指向int的指针”类型,

* fun是“指向返回值为int函数的指针”类型

* arr是“长度为5的int型数组”类型

*/

2.千万不要把typedef嵌到声明的中间部分,如下所示:

unsigned const long typedef int volatile *kumquat;

3.typedef为数据类型创建别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。

typedef int (*array_ptr)[100];

4.应该只对所希望的变量类型进行typedef声明,为变量类型取一个喜欢的别名。关键字typedef应该如前所述出现声明的开始位置。在同一个代码块中,typedef引入的名字不能与其他标识符同名。

5.不要为了方便起见对结构体使用typedef。这样做唯一的好处是能使你不必书写”struct“关键字,但这个关键字可以向你提示一些信息,你不应该把它省掉。应该始终在结构体的定义中使用结构标签,即使它并非必须。这种做法可以使代码更为清晰。

6.typedef应该用在:

数组、结构体、指针以及函数的组合类型。

可移植类型。比如当你需要一种至少20bit的类型时,可以对它进行typedef操作。这样,当把代码移植到不同的平台时,要选择正确的类型如short,int,long时,只要在typedef中进行修改就可以了,无需对每一个声明都加以修改。

typedef也可以为后面的强制类型转换提供一个简单的名字,如:

typedef int (*ptr_to_int_fun)(void);

char * p;

...;

... = (ptr_to_int_fun) p;

c语言 typedef 函数,C语言的typedef相关推荐

  1. C语言 fclose 函数 - C语言零基础入门教程

    目录 一.fclose 函数简介 二.fclose 函数实战 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.fclose 函数简介 ...

  2. C语言 fopen 函数 - C语言零基础入门教程

    目录 一.fopen 函数简介 二.fopen 函数实战 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.fopen 函数简介 C 语 ...

  3. C语言 assert 函数 - C语言零基础入门教程

    目录 一.assert 函数简介 二.assert 函数使用 三.assert 函数用法总结与注意事项 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C ...

  4. C语言 abort 函数 - C语言零基础入门教程

    目录 一.abort 函数简介 二.abort 函数使用 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.abort 函数简介 C 语 ...

  5. C语言 vprintf 函数 - C语言零基础入门教程

    目录 一.vprintf 函数和 printf 函数声明简介 1.printf 函数声明 2.vprintf 函数声明 二.vprintf 函数和 printf 函数使用 三.猜你喜欢 零基础 C/C ...

  6. C语言 strcat_s 函数 - C语言零基础入门教程

    目录 一.strcat_s 函数简介 二.strcat_s 函数原理 三.strcat_s 函数实战 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语 ...

  7. C语言 memcpy_s 函数 - C语言零基础入门教程

    目录 一.memcpy_s 函数简介 1.memcpy 函数报错:error C4996 2.memcpy 函数没有方法来保证有效的缓冲区尺寸,使用不安全 二.memcpy_s 函数语法 三.memc ...

  8. C语言 sizeof 函数 - C语言零基础入门教程

    目录 一.sizeof 函数简介 二.sizeof 函数实战 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.sizeof 函数简介 ...

  9. C语言 sprintf 函数 - C语言零基础入门教程

    目录 一.sprintf 函数简介 二.sprintf 函数使用 三.sprintf/fprintf/printf 函数区别 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 ...

  10. C语言 fwirte 函数 - C语言零基础入门教程

    目录 一.fwirte函数简介 二.fwirte函数使用 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.fwirte函数简介 C 语 ...

最新文章

  1. Python3 基础语法(笔记2)
  2. UML学习总结(1)——UML学习入门
  3. J2SE综合对java util的总结 一
  4. 一种通过变量插值读取属性的方法
  5. vuex最简单、最详细的入门文档
  6. 如何用鲲鹏弹性云服务器部署《Hadoop伪分布式》
  7. python pandas借助pandas-profiling自动生成EDA
  8. Java中的Map List Set等集合类
  9. c语言 勒让德多项式,2406: C语言习题 求n阶勒让德多项式(示例代码)
  10. Overlay 网络 VXLAN 技术解析
  11. 抖音下载android,抖音完整版
  12. 国内优秀开源镜像站汇总
  13. samba文件共享服务器拒绝访问,Samba共享文件夹拒绝访问
  14. java任务监控进度控制
  15. 遇到一位贵人是什么体验,贵人到底有多重要?
  16. 计算机里面怎么建新的文档,【2人回答】怎样在电脑新建中添加Word文档?-3D溜溜网...
  17. TeamViewer试用到期修改MAC地址(解决找不到“网络地址”选项的问题)
  18. 【flex chat】 p2p视频语音聊天室 欢迎你的测试
  19. LSTM 01:理解LSTM原理及训练方法
  20. php找不到localhost下的文件夹,我在localhost里找不到shopImooc下的文件,每次都要手动输入地址,还有就是index.php每次打开都是这样的页面,是数据库没连吗...

热门文章

  1. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java大学生日常行为评分管理系统9gl38(1)
  2. 三个“老掉牙”的推广引流绝招
  3. 计算机里没有摄像这个程序,我的电脑里咋没摄像头图标?
  4. 场景分析原则-5W1H1E
  5. 【网络工程】Linux基础及服务器配置
  6. 变电站应用监控系统6大优势,你知道几个?
  7. 怎么把图片做成gif动图
  8. 网站服务器搭建百青藤,百青藤服务器搭建
  9. cs七龙珠怎么添加机器人_怎么调能让CS龙珠版2.1的机器人笨一点?
  10. 通过360 软件管家,直接安装PinPKM V9.62