`
fireDragonpzy
  • 浏览: 462301 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

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
分享到:
评论

相关推荐

    王桂林老师 c++基础与提高

    最后,王老师通过内联函数的语法和评价、类型转换的不同方式、命名空间的使用以及系统string类的知识,为学习者提供了一个全面的C++基础和提高的知识体系。通过案例分析,如系统string与自定义的MyString类的对比,...

    c++基础与提高.pdf

    ### C++基础知识与提高 #### 1. 综述C++ ##### 1.1. 作者 - **王桂林**: 本书的作者,提供了丰富的C++知识。 ##### 1.1.1. 历史背景 - C++语言由Bjarne Stroustrup于1980年代初期在贝尔实验室开发,旨在为C语言...

    30天掌握c++精髓

    #### 二、C++基础知识篇 ##### 1. 数组与指针 - **数组作为函数参数**:通过传递数组名作为参数,可以实现在函数内部修改外部数组的效果。这种方式实际上是传递数组的首地址,即指针。 - **指针进行排序**:使用...

    C++教程 从零开始C++

    通过上述对C++基础知识的概述,我们可以看到,编程不仅仅是学习语法和规则,更是在于理解和应用这些概念来解决实际问题。C++作为一门功能强大、应用广泛的编程语言,为程序员提供了丰富的工具和框架,帮助他们构建...

    C++笔记:第二章 数据变量和计算

    在C++编程语言中,第二章数据变量和计算是基础章节之一,它主要介绍程序中如何使用变量来存储数据,以及如何通过计算来处理这些数据。本章节详细涵盖了变量的命名规则、基本数据类型的分类、变量的声明与定义、变量...

    C++入门思维导图(自用)

    根据提供的信息,我们可以详细展开关于C++的基础知识点和特性,特别是针对C++的环境搭建、基本使用、命名空间管理、标准库使用以及一些关键特性的介绍。以下是对这些知识点的详细解析: ### 1. C++环境搭建 - **...

    2021 年 C++ 程式设计語言律師等級考試1

    在选择题部分,题目涵盖了C++的基础知识,如语言关键字的用途、类型定义与转换、函数指针、模板、内存管理和对象生命周期等。例如: 1. 第一题考察的是语言本身,答案应为A、C++。 2. 第二题询问具有多种用途的...

    C++语言程序设计基础考试卷分享.pdf

    以上是针对试卷中题目涉及的C++语言基础知识的详细解释。这些知识点涵盖了C++的基本语法、输入输出、类与对象、数组、指针、枚举、函数重载、switch语句、引用以及结构体的使用。掌握这些知识对于理解和编写C++程序...

    大学老师多年阅书整理版C++初学教程

    7. **堆栈、队列结构**:第七章的第三个部分涉及数据结构的基础知识,堆栈和队列是两种常用的数据组织方式,它们在程序设计中有着广泛应用,例如在处理递归问题、任务调度等场景。 8. **动态内存分配**:第七章的第...

    C++练习题2015年下(读程序练习题).pdf

    【知识点详解】 1. **指针与字符串**:在C++中,指针可以用来存储字符串的首地址,使得指针变量如同数组名一样可以访问字符串。例如,`char *str = ...这些知识点涵盖了C++的基础语法和面向对象编程的关键概念。

    面向对象程序设计技术基本数据类型与表达式.pdf

    本篇文档主要介绍了C++中的基本数据类型和表达式,这是理解和编写C++代码的基础。 首先,C++中有五种主要的数据类型:整型、实型、数组、指针和自定义类型(如构造体、联合体和类)。其中,`sizeof`运算符用于获取...

    C+进阶与提高

    ### C++进阶与提高知识点 ...以上知识点构成了《C++进阶与提高》文档的主要内容,涵盖了C++编程的基础知识、特性增强以及面向对象编程的核心概念。通过详细的学习和练习,读者可以进一步提高C++编程水平。

    C语言学习基本框架——Mr.鹏.docx

    鹏分享,旨在帮助初学者掌握C语言的基础知识。 一、C语言模式 C语言程序的核心部分包括主函数`main()`、变量定义和初始化、函数调用和文件包含命令、基本语句以及结束语句。主函数是程序的起点,`int main()`定义...

    #define,const,typedef三者联系与区别

    typedef 只是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),而#define原本在 C 中是为了定义常量,到了 C++,const、enum、inline 的出现使它也渐渐成为了起别名的工具。 typedef 和 #define 的区别...

    C语言版例子C语言版例子

    它是许多现代编程语言的基础,如C++、Java、Python等。 2. **基本语法**:C语言的程序结构包括预处理指令、函数定义、变量声明和语句。其中,`#include`是预处理指令,用于包含头文件;`main()`是程序的入口点;...

    C语言面试汇总.(针对C语言类面试特别设计)

    同时,了解void、struct和enum等复合数据类型。 2. 运算符:掌握算术运算符、关系运算符、逻辑运算符、位运算符等,以及它们的优先级和结合性。 3. 控制流程:理解if-else、switch-case、for、while、do-while等...

Global site tag (gtag.js) - Google Analytics