`

enum类型的本质

    博客分类:
  • C++
阅读更多
enum类型的本质
    至从C语言开始enum类型就被作为用户自定义分类有限集合常量的方法被引入到了语言
当中,而且一度成为C++中定义编译期常量的唯一方法(后来在类中引入了静态整型常量)。
    根据上面对enum类型的描述,到底enum所定义出来的类型是一个什么样的类型呢?作为
一个用户自定义的类型其所占用的内存空间是多少呢?使用enum类型是否真的能够起到有限
集合常量的边界约束呢?大家可能都知道enum类型和int类型具有隐示(自动)转换的规则,
那么是否真的在任何地方都可以使用enum类型的变量来代替int类型的变量呢?下面会逐一
回答这些问题。
    1. 到底enum所定义出来的类型是一个什么样的类型呢?
       在C++中大家都知道仅仅有两种大的类型分类:POD类型和类类型(不清楚的可以参
       见我的其他文章)。enum所定义的类型其实属于POD类型,也就是说它会参与到POD
       类型的隐示转换规则当中去,所以才会出现enum类型与int类型之间的隐示转换现象。
       那么也就是说enum所定义的类型不具备名字空间限定能力(因为不属于类类型),
       其所定义的常量子具备和enum类型所在名字空间相同的可见性,由于自身没有名字
       限定能力,所以会出现名字冲突现象。如:
           struct CEType
           {
               enum EType1 { e1, e2 };
               enum EType2 { e1, e2 };
           };
       上面的例子会出现e1、e2名字冲突编译时错误,原因就在于枚举子(e1、e2)是
       CEType名字空间中的名字,同样在引用该CEType中的枚举子时必须采用CEType::e1
       这样的方式进行,而不是CEType::EType1::e1来进行引用。
    2. 作为一个用户自定义的类型其所占用的内存空间是多少呢?
       该问题就是sizeof( EType1 )等于多少的问题,是不是每一个用户自定义的枚举类
       型都具有相同的尺寸呢?在大多数的32位编译器下(如:VC++、gcc等)一个枚举类
       型的尺寸其实就是一个sizeof( int )的大小,难道枚举类型的尺寸真的就应该是int
       类型的尺寸吗?其实不是这样的,在C++标准文档(ISO14882)中并没有这样来定义,
       标准中是这样说明的:“枚举类型的尺寸是以能够容纳最大枚举子的值的整数的尺寸”,
       同时标准中也说名了:“枚举类型中的枚举子的值必须要能够用一个int类型表述”,
       也就是说,枚举类型的尺寸不能够超过int类型的尺寸,但是是不是必须和int类型
       具有相同的尺寸呢?上面的标准已经说得很清楚了,只要能够容纳最大的枚举子的
       值的整数就可以了,那么就是说可以是char、short和int。例如:
           enum EType1 { e1 = CHAR_MAX };
           enum EType2 { e2 = SHRT_MAX };
           enum EType3 { e3 = INT_MAX  };
       上面的三个枚举类型分别可以用char、short、int的内存空间进行表示,也就是:
           sizeof( EType1 ) == sizeof( char  );
           sizeof( EType2 ) == sizeof( short );
           sizeof( EType3 ) == sizeof( int   );
       那为什么在32位的编译器下都会将上面三个枚举类型的尺寸编译成int类型的尺寸呢?
       主要是从32位数据内存对其方面的要求进行考虑的,在某些计算机硬件环境下具有对
       齐的强制性要求(如:sun SPARC),有些则是因为采用一个完整的32位字长CPU处理
       效率非常高的原因(如:IA32)。所以不可以简单的假设枚举类型的尺寸就是int类
       型的尺寸,说不定会遇到一个编译器为了节约内存而采用上面的处理策略。
    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<EType>( 2  ) );
           func2( static_cast<EType>( -1 ) );
       上面的代码应该很清楚的说明了这样一种异常的情况了,在使用一个操出范围的整
       型值调用func1函数时会导致函数采取不该采取的行为,而第二个函数可能会好一些
       他仅仅是忽略了超出范围的值。这就说明枚举所定义的类型并不是一个真正强类型
       的有限常量集合,这样一种条件下和将上述的两个函数参数声明成为整数类型没有
       任何差异。所以以后要注意标准定义中枚举类型的陷阱。(其实只有类类型才是真
       正的强类型)
      
    4. 是否真的在任何地方都可以使用enum类型的变量来代替int类型的变量呢?
       通过上面的讨论,其实枚举类型的变量和整型变量具有了太多的一致性和可互换性,
       那么是不是在每一个可以使用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 );
       上面的两种情况看是基本上属于同一种类型的问题,其实不然。第一种情况会导致
       编译时错误,会因为std::cin没有定义对应的枚举类型的重载>>运算符而出错,这
       就说明枚举类型是一种独立和鉴别的类型;而第二种情况不会有任何编译时问题,
       但是可能会导致scanf函数栈被破坏而使得程序运行非法,为什么会这样呢?上面
       已经分析过了枚举类型变量的尺寸不一定和int类型相同,这样一来我们采用%d就
       是说将枚举类型变量val当作4字节的int变量来看待并进行参数压栈,而在某些编
       译器下sizeof( val )等于1字节,这样scanf函数就会将val变量地址中的后续的三
       字节地址也压入栈中,并对其进行赋值,也许val变量后续的三个字节的地址没有
       特殊含义可以被改写(比如是字节对齐的空地址空间),可能会认为他不会出现错
       误,其实不然,在scanf函数调用结束后会进行栈清理,这样一来会导致scanf函数
       清理了过多的地址空间,从而破坏了外围函数的栈指针的指向,从而必然会导致程
       序运行时错误。

    由上面的说明枚举类型有那么多的缺点,那我们怎样才能够有一个类型安全的枚举类型
呢?其实可以采用类类型来模拟枚举类型的有限常量集合的概念,同时得到类型安全的好处,
具体参见后续的文章。   文章转自:http://www.cppblog.com/chemz/archive/2007/06/05/25578.html
 

<script src="tag.php?action=relatetag&amp;rtid=136858" type="text/javascript"></script>

分享到:
评论

相关推荐

    enum类型的本质[文].pdf

    《enum类型的本质——深入解析与应用》 在软件开发中,enum类型是一个常见的工具,用于定义一组相关的命名常量。自C语言起,enum就已经被引入,为用户提供了一种定义有限集合常量的方式。在C++中,enum类型进一步...

    枚举语句enum用法详解

    枚举类型本质上是整数类型,可以是`byte`、`sbyte`、`short`、`ushort`、`int`、`uint`、`long`或`ulong`之一,但默认类型为`int`。如果需要指定其他类型,可以在枚举声明时指定: ```csharp enum Colors : byte { ...

    Enum的用法

    #### 一、Enum的本质与特性 `Enum`,作为Java语言中的一个关键字,自JDK 5.0引入以来,便赋予了开发者一种全新的数据类型——枚举类型,其设计初衷在于为编程提供更安全、更简洁的方式来处理固定集合的常量。不同于...

    C语言enum枚举类型解析共13页.pdf.zip

    虽然枚举类型本质上是整型,但不推荐直接进行类型转换,因为这样可能导致意料之外的行为。不过,C语言标准允许将枚举变量赋值给整型变量,反之亦然,但需要注意枚举类型的底层大小可能与int不同。 4. 枚举的大小:...

    Java中的Enum的使用与分析

    值得注意的是,枚举类型本质上是一个特殊的类,它继承自`java.lang.Enum&lt;E&gt;`。这意味着枚举类型可以拥有构造函数、方法和属性,就像任何其他类一样。 #### 枚举的实现机制 当编译上述枚举时,Java编译器会生成一个...

    JavaScript enum枚举类型定义及使用方法

    JavaScript中的枚举类型(enum)并不是语言内建的特性,如C#或Java等其他语言。然而,开发者可以通过模拟枚举的行为来实现类似的功能。在JavaScript中,我们通常使用对象(object)来模拟枚举,就像示例代码中所示。...

    c++中bool enum 引用等學習資料

    2. **枚举值的类型**:默认情况下,枚举值的类型是`int`,但可以通过`enum class`或`enum struct`指定基础类型。 3. **命名空间**:`enum class`或`enum struct`创建的枚举具有自己的作用域,防止与全局或类内的其他...

    枚举enum和switch 的使用

    枚举(Enum)作为编程语言中一种特殊的类型,为开发者提供了一种简洁、清晰的定义一组命名常量的方式。在C#语言中,枚举是通过`enum`关键字定义的,其本质上是一种结构体,与整型(int)紧密相关联,但提供了更丰富...

    javaenum(枚举)使用详解+总结.pdf

    Java中的枚举(enum)是自JDK 1.5版本引入的一种强大的类型,它用于定义一组相关的常量。枚举在Java中被设计为一种特殊的类,它们默认继承自`java.lang.Enum`抽象类,并且是单继承的,这意味着它们无法再继承其他类...

    Java(enum)枚举用法详解

    枚举类型本质上是一种受限制的类,它自动继承自`java.lang.Enum`类,同时也实现了`Comparable`和`Serializable`接口。这意味着枚举实例可以进行比较,并且可以序列化保存。`java.lang.Enum`类的部分声明如下: ```...

    程序设计-枚举类型.pptx

    同时,由于枚举元素本质上是整型常量,系统会为枚举变量分配整数类型所需的存储空间。 总的来说,枚举类型是程序设计中一种非常实用的工具,它帮助我们组织代码,提高代码的可读性和可维护性。通过理解枚举类型的...

    C#数据类型.docC#数据类型.doc

    - **枚举类型**:`enum`。 **引用类型** - **字符串类型**:`string`。 - **数组类型**。 - **类类型**:用户自定义的类。 - **接口类型**。 - **委托类型**。 **特殊类型** - **空类型**:`null`。 - **动态...

    理解 C#值类型与引用类型 (2).docx

    这两种类型的本质差异在于它们如何在内存中存储和处理。 1. 通用类型系统(Common Type System, CTS) CTS是.NET Framework的核心组成部分,它定义了一套标准的数据类型,所有.NET语言编译后的IL代码都基于这些类型...

    java代码-java enum枚举遍历

    由于枚举类型本质上是类,所以它们可以作为参数传递,也可以作为返回类型。此外,枚举可以实现接口,从而实现多态性。 ```java interface Shape { void draw(); } enum Shapes implements Shape { CIRCLE {...

    C#中enum和string的相互转换

    Enum为枚举提供基类,其基础类型可以是除 Char 外的任何整型,如果没有显式声明基础类型,则使用Int32。 注意:枚举类型的基类型是除 Char 外的任何整型,所以枚举类型的值是整型值 1、C#将枚举转为字符串(enume-&gt;...

    C语言数据类型转换的探讨.pdf

    枚举类型(enum)本质上是整型的一种包装,因此枚举常量可以被转换为对应的整型值,反之亦然。但枚举类型的具体底层类型(如int或unsigned int)取决于编译器和平台,因此在跨平台代码中应谨慎使用枚举到整型的转换...

    C语言程序设计其他数据类型PPT学习教案.pptx

    同时,由于枚举类型本质上是整数,所以可以参与常规的整数运算和比较。 5. **枚举变量的作用域** 枚举变量的作用域遵循C语言的一般规则,即定义在哪就作用于哪。如果在函数内部定义,则只在该函数内部可见;如果在...

    跟涛哥一起学嵌入式30:C语言枚举类型深入剖析.pdf

    当我们使用enum定义了一个枚举类型之后,其枚举值列表本质上就是一系列整数值,而且是从0开始依次递增的。尽管在C语言中enum被视为一种数据类型,但它在使用时与整型没有什么区别,既可以作为函数参数、函数返回值,...

    PHP中Enum(枚举)用法实例详解

    在PHP中,枚举(Enum)类型长期以来并没有作为语言的内建类型被支持,但开发者仍可以通过一些方式实现类似枚举的行为。随着PHP版本的更新,PHP社区提供了基于SPL(Standard PHP Library)的扩展库来模拟枚举,以及...

    07-枚举类型.pdf

    枚举常量在本质上是整型常量,可以参与数值运算,例如赋值、比较和算术操作。下面的语句都是合法的: ```c enum weeks today = MON; today = 1; today++; ``` 枚举常量与#define定义的宏常量相似,但它们有区别。...

Global site tag (gtag.js) - Google Analytics