现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

话说enum

2012-11-24 22:57 工业·编程 ⁄ 共 2085字 ⁄ 字号 暂无评论

在C++中,如果一个变量你需要几种可能存在的值,那么就可以被定义成为枚举类型。之所以叫枚举就是说将变量或者叫对象可能存在的情况也可以说是可能的值一一例举出来。

但我并不想说enum怎么定义与怎么说明的,而要说的是enum在C++编译器中是如何处理的。我们先看一个例子:
enum D
{
B,
C
};

const char B = 'B';

int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}

如果按照上面的程序进行编译,会得到如下的编译错误:
error C2365: 'B' : redefinition; previous definition was 'enumerator'
        c:\visual .net project\testenum\testenum\testenum.cpp(24) : see declaration of 'B'
错误的大致的意思是说枚举变量中的枚举元素B重复定义了,可事实上我们并没有定义两个枚举元素B,那是为什么呢?原因在于我们这个时候定义了一个全局的常量B。根据以上的编译错误,似乎我们可以得出一个这么一个结论:在全局作用域里有两个B的定义,且枚举元素B是作为单独变量进行编译的,不受enum D作用域的影响。另外,这个例子更容易出错的版本是这样的,定义两个enum,里面有相同的枚举元素:
enum D
{
B,
C
};

enum E
{
B
}

int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
继续,为了支持上述我的观点并深入研究编译器如何来编译枚举元素,我想通过dump一下看看.rdata区里是不是有一个这样的常量存在,所以我又写了一个这样的程序:
enum HardwareType
{
UNKNOWN = 1000
};

char * p = "Hello Kitty!";

int main()
{
HardwareType c = UNKNOWN;
return 0;
}
用VC++ 2005下自带的dumpbin工具对编译出来的obj文件进行分析,首先看.rdata段是否有这个常量的定义,这里要特别说明一下:一个Windows NT的应用程序典型地拥有9个预定义段,它是.text、 .bss、 .rdata、 .data、 .rsrc、 .edata、 .idata、 .pdata和.debug。这里不详细说每个段的具体含义,只简单说一下我们用到的段,.text段主要包含代码,.rdata段表示只读的数据,比如字符串文字量、常量和调试目录信息。.debug就是一些调试信息.
下面是dump出来的.rdata段的结果:
SECTION HEADER #3
  .rdata name
       0 physical address
       0 virtual address
       D size of raw data
     6E1 file pointer to raw data (000006E1 to 000006ED)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40301040 flags
         Initialized Data
         COMDAT; sym= "`string'" (??_C@_0N@BKAKGEGI@Hello?5Kitty?$CB?$AA@)
         4 byte align
         Read Only

RAW DATA #3
  00000000: 48 65 6C 6C 6F 20 4B 69 74 74 79 21 00           Hello Kitty!.

如上面所示,在.rdata段里只有Hello Kitty!这个常量的数据,没有UNKNOWN的数据,因为1000对应的16进制数为:03E8,在.rdata段里找不到!但千万不要忘记了常量折叠的概念,这个在我上一篇文章中有解释,所以我们还要搜索.text和.debug段, 我们在这两个地方都找到了03E8这个值,出现这种情况只能够说明常量进行了折叠.但这种情况的出现还有两种情形,我觉得有必要再深入研究一下,一种是常量进行了折叠,另一种是预定义宏进行覆盖.所以我又写了一个程序进行了测试:
enum HardwareType
{
UNKNOWN = 1000
};

const int AAA = 100;

char * p = "Hello Kitty!";

int main()
{
&AAA;
&UNKNOWN;
return 0;
}
编译程序会出现如下的编译错误: error C2101: '&' on constant
这又说明了枚举元素UNKNOWN在编译器里的确是以常量来对待的,但它更像宏定义,感觉在预编译期就进行替代.但其实在预编译阶段并没有对枚举元素进行处理.这个原因我想以后说明。
所以综上所述,我们可以得出一个这样的结论: 枚举变量中的枚举元素在编译器中是按照常量来处理的,在所有出现枚举元素的地方你都可以认为它是一个整型常量,编译时枚举元素有名字,但你无法得到它的地址.

给我留言

留言无头像?