枚举大小sizeof中枚举的大小详解

上传人:宝路 文档编号:21420945 上传时间:2017-11-23 格式:DOC 页数:5 大小:41.32KB
返回 下载 相关 举报
枚举大小sizeof中枚举的大小详解_第1页
第1页 / 共5页
枚举大小sizeof中枚举的大小详解_第2页
第2页 / 共5页
枚举大小sizeof中枚举的大小详解_第3页
第3页 / 共5页
枚举大小sizeof中枚举的大小详解_第4页
第4页 / 共5页
枚举大小sizeof中枚举的大小详解_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《枚举大小sizeof中枚举的大小详解》由会员分享,可在线阅读,更多相关《枚举大小sizeof中枚举的大小详解(5页珍藏版)》请在金锄头文库上搜索。

1、至从 C 语言开始 enum 类型就被作为用户自定义分类有限集合常量的方法被引入到了语言当中,而且一度成为 C+中定义编译期常量的唯一方法(后来在类中引入了静态整型常量) 。根据上面对 enum 类型的描述,有以下几个问题:1.到底 enum 所定义出来的类型是一个什么样的类型呢?2.作为一个用户自定义的类型其所占用的内存空间是多少呢?3.使用 enum 类型是否真的能够起到有限集合常量的边界约束呢?4.大家可能都知道 enum 类型和 int 类型具有隐示(自动)转换的规则,那么是否真的在任何地方都可以使用 enum 类型的变量来代替 int 类型的变量呢?1. 到底 enum 所定义出来的

2、类型是一个什么样的类型呢?在 C+中大家都知道仅仅有两种大的类型分类:POD 类型(注(1 ) )和类类型。enum 所定义的类型其实属于 POD 类型,也就是说它会参与到 POD 类型的隐示转换规则当中去,所以才会出现 enum 类型与 int 类型之间的隐示转换现象。那么也就是说 enum 所定义的类型不具备名字空间限定能力(因为不属于类类型) ,其所定义的常量子具备和 enum 类型所在名字空间相同的可见性,由于自身没有名字限定能力,所以会出现名字冲突现象。如:struct CETypeenum EType1 e1, e2 ;enum EType2 e1, e2 ;上面的例子会出现 e1

3、、e2 名字冲突编译时错误,原因就在于枚举子(e1 、e2)是 CEType名字空间中的名字,同样在引用该 CEType 中的枚举子时必须采用 CEType:e1这样的方式进行,而不是 CEType:EType1:e1来进行引用。注(1)POD 类型:你可以将 POD 类型看作是一种来自外太空的用绿色保护层包装的数据类型,POD 意为“Plain Old Data”(译者:如果一定要译成中文,那就叫“彻头彻尾的老数据 ”怎么样!)这就是 POD 类型的含义。其确切定义相当粗糙(参见 C+ ISO 标准) ,其基本意思是 POD 类型包含与 C 兼容的原始数据。例如,结构和整型是 POD 类型,

4、但带有构造函数或虚拟函数的类则不是。 POD 类型没有虚拟函数,基类,用户定义的构造函数,拷贝构造,赋值操作符或析构函数。为了将 POD 类型概念化,你可以通过拷贝其比特来拷贝它们。此外, POD 类型可以是非初始化的。2. 作为一个用户自定义的类型其所占用的内存空间是多少呢?该问题就是 sizeof( EType1 )等于多少的问题,是不是每一个用户自定义的枚举类型都具有相同的尺寸呢?在大多数的32位编译器下(如: VC+、gcc 等)一个枚举类型的尺寸其实就是一个 sizeof( int )的大小,难道枚举类型的尺寸真的就应该是 int 类型的尺寸吗?其实不是这样的,在 C+标准文档(IS

5、O14882)中并没有这样来定义, 标准中是这样说明的:“枚举类型的尺寸是以能够容纳最大枚举子的值的整数的尺寸” ,同时标准中也说名了:“枚举类型中的枚举子的值必须要能够用一个 int 类型表述” , 也就是说,枚举类型的尺寸不能够超过 int 类型的尺寸,但是是不是必须和 int 类型具有相同的尺寸呢?上面的标准已经说得很清楚了,只要能够容纳最大的枚举子的值的整数就可以了,那么就是说可以是 char、short 和 int。例如:enum EType1 e1 = CHAR_MAX ;enum EType2 e2 = SHRT_MAX ;enum EType3 e3 = INT_MAX ;上面

6、的三个枚举类型分别可以用 char、short 、int 的内存空间进行表示,也就是:sizeof( EType1 ) = sizeof( char );sizeof( EType2 ) = sizeof( short );sizeof( EType3 ) = sizeof( int );那为什么在32位的编译器下都会将上面三个枚举类型的尺寸编译成 int 类型的尺寸呢?主要是从32位数据内存对其方面的要求进行考虑的,在某些计算机硬件环境下具有对齐的强制性要求(如:sun SPARC) ,有些则是因为采用一个完整的32位字长 CPU 处理效率非常高的原因(如: IA32) 。所以不可以简单的假

7、设枚举类型的尺寸就是 int 类型的尺寸,说不定会遇到一个编译器为了节约内存而采用上面的处理策略。3. 使用 enum 类型是否真的能够起到有限集合常量的边界约束呢?首先看一下下面这个例子:enum EType e1 = 0, e2 ;void func1( EType e )if ( e = e1 )/ do something/ do something because e != e1 must e = e2void func2( EType e )if ( e = e1 )/ do somethingelse if ( e = e2 )/ do somethingfunc1( stati

8、c_cast( 2 ) );func2( static_cast( -1 ) );上面的代码应该很清楚的说明了这样一种异常的情况了,在使用一个操出范围的整型值调用func1函数时会导致函数采取不该采取的行为,而第二个函数可能会好一些他仅仅是忽略了超出范围的值。这就说明枚举所定义的类型并不是一个真正强类型的有限常量集合,这样一种条件下和将上述的两个函数参数声明成为整数类型没有任何差异。所以以后要注意标准定义中枚举类型的陷阱。(其实只有类类型才是真正的强类型)4. 是否真的在任何地方都可以使用 enum 类型的变量来代替 int 类型的变量呢?通过上面的讨论,其实枚举类型的变量和整型变量具有了太多

9、的一致性和可互换性,那么是不是在每一个可以使用 int 类型的地方都可以很好的用枚举类型来替代呢?其实也不是这样的,毕竟枚举类型是一个在编译时可区分的类型,同时第2点的分析枚举类型不一定和 int 类型具有相同的尺寸,这两个差异就决定了在某些场合是不可以使用枚举类型来代替 int 类型的。如:第一种情况:enum EType e1 = 0, e2, e3 ;EType val;std:cin val;第二种情况:enum EType e1 = 0, e2, e3 ;EType val;std:scanf( %d, &val );上面的两种情况看是基本上属于同一种类型的问题,其实不然。第一种情况

10、会导致编译时错误,会因为 std:cin 没有定义对应的枚举类型的重载运算符而出错,这就说明枚举类型是一种独立和鉴别的类型;而第二种情况不会有任何编译时问题,但是可能会导致 scanf 函数栈被破坏而使得程序运行非法,为什么会这样呢?上面已经分析过了枚举类型变量的尺寸不一定和 int 类型相同,这样一来我们采用%d 就是说将枚举类型变量 val 当作4字节的 int 变量来看待并进行参数压栈,而在某些编译器下 sizeof( val )等于1 字节,这样 scanf 函数就会将 val 变量地址中的后续的三字节地址也压入栈中,并对其进行赋值,也许 val 变量后续的三个字节的地址没有特殊含义可

11、以被改写(比如是字节对齐的空地址空间) ,可能会认为他不会出现错误,其实不然,在 scanf 函数调用结束后会进行栈清理,这样一来会导致 scanf 函数清理了过多的地址空间,从而破坏了外围函数的栈指针的指向,从而必然会导致程序运行时错误。由上面的说明枚举类型有那么多的缺点,那我们怎样才能够有一个类型安全的枚举类型呢?实际上,在最新的 C+0x 标准草案中有关于枚举作用域问题的提案,但最终的解决方案会是怎样的就无法未卜先知了,毕竟对于象 C+ 这样使用广泛的语言来说,任何特性的增删和修改都必须十分小心谨慎。当然,我们可以使用一些迂回的方法来解决这个问题(C+ 总是能给我们很多惊喜和意外) 。例

12、如,我们可以把枚举值放在一个结构里,并使用运算符重载来逼近枚举的特性:struct FileAccess enum _Enum Read = 0x1,Write = 0x2;_Enum _value; / 枚举值FileAccess(int value = 0) : _value(_Enum)value) FileAccess& operator=(int value) this-_value = (_Enum)value;return *this;operator int() const return this-_value;我们现在可以按照希望的方式使用这个枚举类型:FileAccess

13、access = FileAccess:Read;并且,因为我们提供了到 int 类型的转换运算符,因此在需要 int 的地方都可以使用它,例如 switch 语句:switch (access) case FileAccess:Read:break;case FileAccess:Write:break;当然我们不愿意每次都手工编写这样的结构。通过使用宏,我们可以很容易做到这一点:#define DECLARE_ENUM(E) struct E public: E(int value = 0) : _value(_Enum)value) E& operator=(int value) this-_value = (_Enum)value; return *this; operator int() const return this-_value; enum _Enum #define END_ENUM() ; private: _Enum _value; ;我们现在可以按如下的方式定义前面的枚举,并且不比直接写 enum 复杂多少。DECLARE_ENUM(FileAccess)Read = 0x1,Write = 0x2,END_ENUM()DECLARE_ENUM(FileShare)Read = 0x1,Write = 0x2,END_ENUM()

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号