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

上传人:工**** 文档编号:544209477 上传时间:2023-09-05 格式:DOC 页数:5 大小:41KB
返回 下载 相关 举报
枚举大小sizeof 中枚举的大小详解.doc_第1页
第1页 / 共5页
枚举大小sizeof 中枚举的大小详解.doc_第2页
第2页 / 共5页
枚举大小sizeof 中枚举的大小详解.doc_第3页
第3页 / 共5页
枚举大小sizeof 中枚举的大小详解.doc_第4页
第4页 / 共5页
枚举大小sizeof 中枚举的大小详解.doc_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

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

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

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

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

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

5、够容纳最大枚举子的值的整数的尺寸”, 同时标准中也说名了:“枚举类型中的枚举子的值必须要能够用一个int类型表述”, 也就是说,枚举类型的尺寸不能够超过int类型的尺寸,但是是不是必须和int类型具有相同的尺寸呢? 上面的标准已经说得很清楚了,只要能够容纳最大的枚举子的值的整数就可以了,那么就是说可以是char、short和int。 例如: enum EType1 e1 = CHAR_MAX ; enum EType2 e2 = SHRT_MAX ; enum EType3 e3 = INT_MAX ; 上面的三个枚举类型分别可以用char、short、int的内存空间进行表示,也就是: si

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

7、。 3. 使用enum类型是否真的能够起到有限集合常量的边界约束呢? 首先看一下下面这个例子: enum EType e1 = 0, e2 ; void func1( EType e ) if ( e = e1 ) / do something / do something because e != e1 must e = e2 void func2( EType e ) if ( e = e1 ) / do something else if ( e = e2 ) / do something func1( static_cast( 2 ) ); func2( static_cast( -1

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

9、好的用枚举类型来替代呢? 其实也不是这样的,毕竟枚举类型是一个在编译时可区分的类型, 同时第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 ); 上面的两种情况看是基本上属于同一种类型的问题,其实不然。第一种情况会导致编译时错误, 会因为std:cin没有定义对应的枚举

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

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

12、ccess 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 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)

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

当前位置:首页 > 生活休闲 > 社会民生

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