C语言的typedef

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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容