CC++中tag和type

更新时间:2023-07-18 20:23:50 阅读: 评论:0

CC++中tag和type
C语⾔将tag视作⼆等公民类型.C++却没这么友好.本⽂阐述在C/C++中如何给tag头等公民类型待遇.
在编程语⾔中,标识符是最主要的基本元素,被⽤来对函数,对象,常量,类型等实体命名。
在C/C++⾥,⼀个标识符是由字母或下划线开头后接0个或多个字母,下划线或数字的字符序列。标识符是⼤⼩写敏感的,所以DAN,Dan,dan是不同的标识符。
在我对C语⾔的认知⾥,C把结构,联合和枚举的标识符当做⼆等公民看待。⼀个命名了结构,联合或枚举的标识符也命名了⼀个类型,但你没法在typedef中使⽤这个标识符来代表那个类型。
这个⽉,我研究了这个表⾯清楚实际很混乱的奇怪⾏为,这同样也存在于C++中。我将给出⼀种简单的编程风格来终⽌这种混乱。
C中的tag石碳酸
在C⾥,出现在下⾯的名字:
struct s
困扰是什么意思
{
...
};
是⼀个tag。⼀个单独的tag不是⼀个类型名。假如是的话,C编译器应该允许如下的声明:
s x;  // error in C
s *p;  // error in C
实际上C编译器不允许这样的声明。你必须如下声明:
struct s x;  // OK
struct s *p;  // OK
struct后跟s的组合,被称作详细类型说明符(elaborated type specifier).
联合和枚举的名字也是tag⽽并⾮类型。例如:
enum day { Sunday, Monday, ... };
...
day today;  // error
enum day tomorrow; // OK
这⾥,enum day就是⼀个详细类型说明符。
基本上,C不允许在同⼀作⽤域中出现重名的个体。例如同⼀作⽤域中的如下声明:
int status();  // function
int status;  // object
编译器将指出后⼀个声明错误。但是C对待tag却不同于其它标识符。C编译器将tag保存在⼀个符号表中,在概念上(⽽⾮物理上)与符号表中其它的标识符分离。因此,C程序员可以在同⼀作⽤域中拥有同名的tag和标识符。
例如,C编译器允许:
int status();  // function
enum status { ... }; // enumeration
在同⼀作⽤域中。甚⾄下⾯的也OK:
struct s s;
这定义了⼀个类型是struct s的对象s。这样的声明不是好的习惯,可这是C。。。
tag和typedef
很多程序员倾向于把结构体tag当做类型名,所以他们⽤typedef为tag定义别名。例如:
struct s
{
仰卧起坐的作用与功效
...
};
typedef struct s T;
允许你使⽤T来代替struct s:
T x; // OK
T *p; // OK
程序不能定义⼀个类型为T名字也为T的对象(或函数或枚举常量),例如:
T T;  // error
这很好。
注意:我在gcc 4.4.7上实验发现,T T;这样的定义是可以的。
结构,联合或枚举定义中的tag名是可选的。很多程序员将结构定义合并到typedef中并分配⼀个tag:
typedef struct
{
.
..
} T;
这没问题,除⾮结构体成员中引⽤了结构体本⾝:
struct list_node
{
...
struct list_node *next;
};
定义了结构体list_node,其中包含指向另⼀个list_node的指针。如果你⽤typedef定义结构体并省略tag,例如:
typedef struct
{
...
list_node *next; // error
} list_node;
编译器会报错,因为成员变量next的定义在list_node被声明之前就引⽤list_node了。
对于引⽤⾃⾝的结构体,我们除了声明⼀个结构体的tag外别⽆他法。如果你希望之后使⽤typedef的名字,你必须同时声明tag和typedef。很多程序员遵循K&R建议的命名习惯。在他们初版的书中,他们为tag选了⼀个短⼩,有点隐晦的标识符,并为typedef选了⼀个长的⼤写的标识符。如下:
typedef struct tnode
{
...
struct tnode *left;
struct tnode *right;
} TREENODE;
在书的第⼆版⾥,他们把TREENode改为Treenode。
我始终不能理解为什么他们为tag和typedef使⽤不同的名字,使⽤⼀个名字也没有不妥:
typedef struct tree_node tree_node;
更进⼀步,你可以在结构体定义之前⽽不是之后,提前声明结构体:
typedef struct tree_node tree_node;
struct tree_node
{
...
回南天怎么防潮
tree_node *left;
tree_node *right;
};
你⽆需在声明成员变量时使⽤关键字struct,诸如left和right之类,引⽤的是另外⼀个tree_nodes。
C++中的tag
C++中类的语法是结构和联合语法的扩展。实际上,C++把结构和联合当做类的特殊情况,我也是。主播自我介绍
尽管C++标准没有管它们叫tag,类的名字实际上⾮常像tag。例如,你可以声明class string的对象如下:
class string s;
当然,很少(如果有的话),C++程序员真的这么做。
C++把⽤户定义类型设计为看起来很像内建类型。内建类型的声明如下:
int n;
不必使⽤关键字class,所以前⾯使⽤了class关键字的s的声明会让提醒你这不是⼀个内建类型。为此,C++允许你省略class关键字,像使⽤类型名⼀样直接使⽤类名,如:
string s;
再次,C++标准从没使⽤过tag这个词。在C++中,类和枚举名就是类型名。尽管,有若⼲条规则⽤来选出这些类型名并区别对待。我发现继续把类名和枚举名看做tag会更容易理解。
如果你愿意,你可以想象C++⾃动为每⼀个tag⽣成了⼀个typedef。例如,当编译器遇到了如下的类定义:
class gadget
{
...
};
会⾃动⽣成⼀个typedef,如同程序定义⼀样:
玫瑰花苞typedef class gadget gadget;
不幸的是,这并⾮完全准确。C++不能为结构,联合或枚举⽣成这样的typedef,它并不能兼容C的指
令。
例如,假设C程序声明了⼀个函数和⼀个结构体名字都是query:
大饼int query();
struct query;
再次,这可能是坏的编程⾏为,但仍然可能真实发⽣,⽐如不同作者在不同的⽂件中定义了同名的函数和结构体。不管怎样,query都能代表函数⽽struct query代表结构体。
紫色如果C++真的⾃动为tag⽣成typedef,那么当你在C++中编译上⾯这个程序,编译器应该⽣成:
typedef struct query query;
很不幸,这个类型名会与函数名冲突,程序⽆法编译通过。
在C++中,tag表现得就像typedef⼀个名字,除⾮程序在相同作⽤域声明了⼀个跟tag同名的对象,函数,或枚举。在这种情况下,对象,函数或枚举名屏蔽了tag名,程序要想引⽤tag名只能在tag名前⾯追加关键字class,struct,union或enum。因此,⼀个包含如下语句的C程序:
int query();
struct query;
跟在C++下编译的程序⾏为⼀致。再次,query代表函数,详细类型说明符struct query代表类型。
防⽌不⼩⼼让⾮类型名屏蔽tag的⽅法是有意⽤⼀个typedef屏蔽掉tag名。每⼀次你声明⼀个tag,你应该也定义⼀个同名typedef来重命名tag,就像:
typedef class gadget gadget;
class gadget
{
...
};
这样,如果同⼀作⽤域中有同名的函数,对象或枚举常量,你会得到⼀个编译器的明显错误信息,⽽不是只能在运⾏时才能追踪到的隐蔽bug。
推荐准则
我的建议是,采⽤同⼀风格来转换tag为typedef。
对每⼀个tag,在同⼀作⽤域中定义⼀个同名的typedef作为tag的别名。
这种风格在C和C++中都能正常运作。
对每⼀个class,你可以把typedef定义在类定义前⾯或后⾯(C++中的class包括结构和联合)。把typedef放在类定义之前可以让你让你在类中使⽤typedef的定义,所以这是我推荐的。
对每⼀个枚举,你必须把typedef放在枚举定义之后,如:
enum day { Sunday, Monday, ... };
typedef enum day day;  // OK
放在前⾯会触发编译时错误:
typedef enum day day;  // error
enum day { Sunday, Monday, ... };
应当承认,tag名被屏蔽印发错误的进率看起来很⼩。你可能永远不会遇到这样的问题。但是⼀旦这样的错误出现就很致命,所以你还是应该使⽤typedef不管这种错误发⽣⼏率有多⼩。
我不能理解为什么有⼈允许在同⼀作⽤域中让函数或对象名屏蔽类名。这种屏蔽规则在C中是⼀个失误,本不应该在C++中继续存在。你需要付出更多的编程努⼒来避免这个问题。
本⽂作者:Dan Saks is the president of Saks & Associates, a C/C++ training and consulting company. He rved for many years as cretary of the C++ standards committee. With Thomas Plum, he wrote C++ Programming Guidelines. You can write to him at .

本文发布于:2023-07-18 20:23:50,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1103708.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:类型   结构   定义   函数   声明   标识符   联合
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图