C语言的联合(union)与枚举(enum)

联合(union)

联合(union)在许多其他语言中被称为变体记录(variant record)。它的外表与结构体相似,但在内存布局上存在关键性的区别。在结构体中,每个成员依次存储,而在联合中,所有的成员都从偏移地址零开始存储。这样,每个成员的位置都重叠在一起;在某一时刻,只有一个成员真正存储于该地址。

联合既有一些优点,也有一些缺点。它的缺点就是那些所谓的优点其实并不怎么出色。联合的优点是它的外观同结构体一样,只是用关键字union取代了关键字struct。所以,如果你对结构体的一切都已了如指掌,基本上也就掌握了联合。联合的一般形式如下:

union 联合标签(可选){
  类型1 标识符1;
  类型2 标识符2;
  ...
  类型N 标识符N;
}变量定义(可选);

联合一般是作为大型结构的一部分存在的。在有些大型结构中,存在一些与实际表示的数据类型有关的隐式或显式的信息。如果存储数据时是一种类型,但在提取该数据时却成了另外一种类型,这显然存在着明显的类型不安全性。在Ada语言中,所有不同类型的字段都显式的存储于记录中,这就避免了这个问题。C语言则含糊的多,让程序员自己去回忆放在那儿的究竟是什么东西。

联合一般用来节省空间,因为有些数据项是不可能同时出现的,如果同时存储它们,显然颇为浪费。例如,如果我们要存储一些关于动物种类的信息,首先想到的方法可能是:

struct creature{
  char has_backbone;
  char has_fur;
  short num_of_legs_in_excess_of_4;
};

但是,我们知道,所有的动物要么是脊椎动物,要么是无脊椎动物。进而,我们还知道只有脊椎动物才可能有毛皮,只有无脊椎动物才可能有多于4条的腿。没有一种动物既有毛皮又有超过4条的腿。这样,可以通过把两个互相排斥的字段存储于一个联合中来节省空间:

union secondary_characteristics{
  char has_fur;
  short num_of_legs_in_excess_of_4;
};
struct creature{
  char has_backbone;
  union secondary_characteristics form;
};

我们通常采取这种方式来节省备用的存储空间。如果我们有一个数据文件,里面存储了20000000个动物,使用这种方法,可以节省大约20MB的磁盘空间。

然而,联合还有其他用途,联合也可以把同一个数据解释成两种不同的东西,而不是把两个不同的数据解释为一个东西。该用法例子如下:

union bits32_tag{
  int whole; //一个32位的值
  struct { char c0, c1, c2, c3;} bytes; //4个8位的字节
} value;

这个联合允许程序员提取整个32位值(作为 int),也可以提取单独的字节字段如value.bytes.c0等。采用其他的方法也能达到这个目的,但联合不需要额外的赋值或强制类型转换。

在实际工作中,结构体的使用比联合多得多。

枚举(enum)

枚举(enum)通过一种简单的途径,把一串名字与一串整型值联系在一起。对于像C这样的弱类型语言而言,很少有什么事只能靠枚举而不能用#define来解决的。枚举的一般形式:

enum 可选标签 {内容...} 可选变量定义;

其中的“内容...”是把一些标识符的列表,可能有一些整型值赋给它们。下面是一个枚举实例:

enum sizes { small = 7, medium, large = 10, humungous };

缺省情况下,整型值从0开始。如果对列表中的某个标识符进行了赋值,那么紧接其后的那个标识符的值就比所赋的值大1,然后类推。枚举具有一个优点:#define 定义的名字一般在编译时被丢弃,而枚举名字则通常一直在调试器中可见,可以在调试代码时使用它们。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 32,142评论 2 89
  • 注:这是第三遍读《C语言深度解剖》,想想好像自从大学开始就没读完过几本书,其中谭浩强的那本《C语言程序设计(第四版...
    HavenXie阅读 5,755评论 1 6
  • 亲爱的儿子: 这个寒假转眼就结束了,明早你又要背起你那沉重的连妈妈都提不动的书包去上学了。新的起点又开...
    Rain妈妈阅读 3,971评论 0 0
  • 很多时候我们在执行setState之后再执行某些方法,如果单纯把该方法放到setState函数之后,你可能会很惊奇...
    meluyue阅读 2,773评论 0 2
  • 既然选择了远方,便只顾风雨兼程! 关于es6我也只是跟开始接触,说的不好请大家多多关照,希望能对学习前端的朋友一点...
    chasing_dream阅读 1,943评论 0 2