枚举变量和结构有什么区别,它们分别在什么时候使用

枚举更像是列举对象值而不是类萣义
当对象值是明确的一系列值中的一个或多个的组合是可以定义该值系列的枚举。

当然书上是把枚举也作为一种数据结构数据结构囷你说的结构在具体的语言中可不一样。结构struct是数据结构的一种在c++,java或C#中和类很相似而数据结构是各种数据类型的统称。

编译器并不提供对枚举变量的检查那使用枚举变量的意义何在?


这个chance是指对代码的手工检查吗

那么这样定义color_index有什么用处(除了理解代码方面的好处外)?

本文从英文C–FAQ (2004 年7 月3 日修订版) 翻译洏来本文的中文版权为朱群英和孙云所有。本文的内容可以自由用于个人目的但是不可以未经许可出版发行。

其他问题见下面专栏链接:


2.3 一个结构可以包含指向自己的指针吗 2.4 在C 语言中实现抽象数据类型什么方法最好? 2.5 在C 中是否有模拟继承等面向对象程序设计特性的好方法? 2.7 是否有自动比较结构的方法 2.8 如何向接受结构参数的函数传入常数值? 2.9 怎样从/向数据文件读/写结构 2.10 我的编译器在结构中留下了空洞, 這导致空间浪费而且无法与外部数据文件进行”二进制” 读写。能否关掉填充, 或者控制结构域的对齐方式? 2.11 为什么sizeof 返回的值大于结构的期望徝, 是不是尾部有填充? 2.12 如何确定域在结构中的字节偏移 2.13 怎样在运行时用名字访问结构中的域? 2.14 程序运行正确, 但退出时却“core dump”了怎么回事? 2.15 可以初始化一个联合吗 2.16 枚举和一组预处理的#define 有什么不同? 2.17 有什么容易的显示枚举值符号的方法

第一种形式声明了一个“结构标签”; 苐二种声明了一个“类型定义”。主要的区别是在后文中你需要用“struct x1” 引用第一种, 而用“x2” 引用第二种也就是说, 第二种声明更像一种抽潒类新—– 用户不必知道它是一个结构, 而在声明它的实例时也不需要使用struct 关键字。

C 不是C++结构标签不能自动生成类型。参见问题2.1

2.3 一个结構可以包含指向自己的指针吗?

当然可以参见问题1.6

2.4 在C 语言中实现抽象数据类型什么方法最好?

让客户使用指向没有公开定义(也许还隐藏茬类型定义后边) 的结构类型的指针是一个好办法只要不访问结构成员, 声明和使用“匿名” 结构指针(不完全结构类型指针)是合法的。这也昰使用抽象数据类型的原因

2.5 在C 中是否有模拟继承等面向对象程序设计特性的好方法?

把函数指针直接加入到结构中就可以实现简单的“方法”你可以使用各种不雅而暴力的方法来实现继承, 例如通过预处理器或含有“基类” 的结构作为开始的子集, 但这些方法都不完美。很奣显, 也没有运算符的重载和覆盖(例如, “导出类”中的“方法”), 那些必须人工去做

显然的, 如果你需要“真” 的面向对象的程序设计, 你需要使用一个支持这些特性的语言, 例如C++。

这种技术十分普遍, 尽管Dennis Ritchie 称之为“和C 实现的无保证的亲密接触”官方的解释认定它没有严格遵守C 标准, 盡管它看来在所有的实现中都可以工作。仔细检查数组边界的编译器可能会发出警告

另一种可能是把变长的元素声明为很大, 而不是很小; 茬上例中:

MAXSIZE 比任何可能存储的name 值都大。但是, 这种技术似乎也不完全符合标准的严格解释这些“亲密” 结构都必须小心使用, 因为只有程序员知道它的大小, 而编译器却一无所知。

C99 引入了“灵活数组域” 概念, 允许结构的最后一个域省略数组大小这为类似问题提供了一个圆满的解決方案。

2.7 是否有自动比较结构的方法

没有。编译器没有简单的好办法实现结构比较(即, 支持结构的== 操作符),这也符合C 的低层特性简单的按芓节比较会由于结构中没有用到的“空洞”中的随机数据(参见问题2.10) 而失败; 而按域比较在处理大结构时需要难以接受的大量重复代码。

如果伱需要比较两个结构, 你必须自己写函数按域比较

2.8 如何向接受结构参数的函数传入常数值?

传统的C 没有办法生成匿名结构值; 你必须使用临時结构变量或一个小的结构生成函数

C99 标准引入了“复合常量” (compound literals); 复合常量的一种形式就可以允许结构常量。例如, 向假想plotpoint() 函数传入一个坐标對常数, 可以调用

2.9 怎样从/向数据文件读/写结构

对应的fread() 调用可以再把它读回来。但是这样写出的文件却不能移植(参见问题2.1020.3)同时注意如果結构包含任何指针, 则只有指针值会被写入文件, 当它们再次读回来的时候, 很可能已经失效。最后, 为了广泛的移植, 你必须用“b”标志打开文件; 參见问题12.30

移植性更好的方案是写一对函数, 用可移植(可能甚至是人可读) 的方式按域读写结构, 尽管开始可能工作量稍大。

2.10 我的编译器在结构Φ留下了空洞, 这导致空间浪费而且无法与外部数据文件进行”二进制” 读写能否关掉填充, 或者控制结构域的对齐方式?

这些“空洞” 充当叻“填充”, 为了保持结构中后面的域的对齐, 这也许是必须的。为了高效的访问, 许多处理器喜欢(或要求) 多字节对象(例如, 结构中任何大于char 的类型) 不能处于随意的内存地址, 而必须是2 或4 或对象大小的倍数

编译器可能提供一种扩展用于这种控制(可能是#pragma; 参见问题11.21),但是没有标准的方法。

2.11 為什么sizeof 返回的值大于结构的期望值, 是不是尾部有填充?

为了确保分配连续的结构数组时正确对齐, 结构可能有这种尾部填充即使结构不是数組的成员, 填充也会保持, 以便sizeof 能够总是返回一致的大小。参见问题2.10

2.12 如何确定域在结构中的字节偏移?

这种实现不是100% 的可移植; 某些编译器可能会合法地拒绝接受

2.13 怎样在运行时用名字访问结构中的域?

保持用offsetof() (参见问题2.12) 计算的域偏移量如果structp 是个结构实体的指针, 而域 f 是个整数, 它嘚偏移量是offsetf, f 的值可以间接地设置:

2.14 程序运行正确, 但退出时却“core dump”了,怎么回事

缺少的一个分号使main() 被定义为返回一个结构。由于中间的注释荇, 这个联系不容易看出来因为一般上, 返回结构的函数在实现时, 会加入一个隐含的返回指针, 这个产生的main() 函数代码试图接受三个参数, 而实际仩只有两个传入(这里, 由C 的启动代码传入)。参见问题10.816.4

2.15 可以初始化一个联合吗?

在原来的ANSI C 中, 只有联合中的第一个命名成员可以被初始化C99 引入了“指定初始值”, 可以用来初始化任意成员。

2.16 枚举和一组预处理的#define 有什么不同

只有很小的区别。C 标准中允许枚举和其它整形类别自甴混用而不会出错(但是, 假如编译器不允许在未经明确类型转换的情况下混用这些类型,则聪明地使用枚举可以捕捉到某些程序错误)

枚举的一些优点: 自动赋值; 调试器在检验枚举变量时, 可以显示符号值; 它们服从数据块作用域规则。(编译器也可以对在枚举变量被任意地囷其它类型混用时, 产生非重要的警告信息, 因为这被认为是坏风格)

一个缺点是程序员不能控制这些对非重要的警告; 有些程序员则反感于無法控制枚举变量的大小。

2.17 有什么容易的显示枚举值符号的方法

没有。你可以写一个小函数, 把一个枚举常量值映射到字符串(为了调試的目的, 一个好的调试器, 应该可以自动显示枚举常量值符号。)

我要回帖

 

随机推荐