C++ 中的 enum 结构在内存中是怎么存储的?

C++ 中的 enum 结构在内存中是怎么存储的?里面存储的是常量值吗?

 

关于占用内存的大小,enum类型本身是不占内存的,编译器直接替换。但是enum类型的变量肯定是占内存的(关于占用内存的大小,看后面详述)。

enum需要特别注意的是它的取值范围和类型分配。

关于确定enum的取值范围,如果一个enum中所有的枚举值非负,那么枚举的表示范围是[0,2^k - 1],其中2^k是使得所有枚举值位于此范围内的最小的2的幂。如果是有负值,那么范围就是[-2^k,2^k-1]。因此对一个给定的整数值,如果使用强制转换,而其值又不在枚举的表示范围以内,其行为是未定义的。
举一个例子:

 
  1. enum EnumTest{
  2. a =1,b = 5};

其中没有负数,最大值是5,二进制表示是101,需要3bits能够容纳下。因此取值范围是[0,7]。

 
  1. enum EnumTest{
  2. a =-2,b = 5};

绝对值最大的是5,需要3bits能够容纳下,但是因为有负值,需要增加一个符号位,于是需要4bits,取值范围是[-8,7]。
C++规定枚举的大小只要能够容纳下3bits或者4bits(上面的例子)就行,至于分配1byte还是4bytes,是编译器决定的,但是C++标准有个限制:1<=sizeof(enum)<=sizeof(int)。

实例代码:

 
  1. #include <iostream>
  2. using namespace std;
  3. class A{
  4. public:
  5. //enum类型本身不占内存
  6. enum EnumTest{
  7. a =1,b = 5};
  8. };
  9. enum EnumTest{
  10. a =1,b = 5};
  11. class B{
  12. public:
  13. private:
  14. //enum理想的变量会占用内存
  15. enum EnumTest enumSample1;
  16. };
  17. int main()
  18. {
  19. enum EnumTest{
  20. a =1,b = 5};
  21. cout << sizeof(enum EnumTest) << endl;
  22. //注意:此处结果是未定义的
  23. enum EnumTest enumSample1 = (enum EnumTest)10;
  24. cout << enumSample1 << endl;
  25. cout << "sizeof(Class A) = " << sizeof(A) << endl;
  26. cout << "sizeof(Class B) = " << sizeof(B) << endl;
  27. return 0;
  28. }

运行结果:

最后,给你提供好的参考资料:
what is the size of an enum type data in C++?

2
 

个人觉得谈论enum的内存分布没有太大的意义,因为enum中的值是在编译阶段就确定了。
虽然我们可以写出如下的代码:

 
  1. enum DefType{
  2. a = 1,
  3. b = 5
  4. };
  5. DefType testDefType; // 创建一个enum DefType的变量

但若像结构体一样调用testDefType.a,则不能通过编译。
若我们在函数外写下如下的语句:

 
  1. enum DefType{
  2. a = 1,
  3. b = 5
  4. };
  5. enum DefType2{
  6. a = 10,
  7. b2 = 50
  8. };

这样编译不会通过:error C2365: “a”: 重定义;以前的定义是“枚举数”。

关于enum的语法细节,楼上几位已经说的很详细了,不在赘述,只是举个enum常用的例子。

 
  1. class AA{
  2. enum DefType{
  3. a = 10,
  4. b = 5
  5. };
  6. int arr[a];
  7. };
  8. class BB{
  9. enum DefType2{
  10. a = 100,
  11. b2 = 50
  12. };
  13. int arr[a];
  14. };

这也是在类中静态声明一个数组的好方法称为enum hack。

@卢俊的答案说对了一半,宏虽然是在预处理阶段做了替换,但enum值不是在运行时确定,而是在编译时确定,从生成的汇编代码可以证明:

 
  1. ; 16 : int e = E;
  2. mov DWORD PTR _e$[ebp], 4
  3. ; 17 :
  4. ; 18 : int a = A;
  5. mov DWORD PTR _a$[ebp], 0
2
thebest 267天前

1

补充:enum结构体定义的的确是常量,但并不是在预编译的时候进行替换,而是在运行时,从enum定义的常量存储区取定义的常量值。因此,同样的常量定义,如果用#define,代码中多处用到该常量的话,编译出来的会比用enum定义使用的常量存储区大,下面这段程序:

//示例代码 a.c

#include <stdio.h>

#define E 4

enum ST
{
A,
B,
C,
D
};

void main()
{
int e = E;

int a = A;
}

使用预编译指令来预编译这段代码:

$ gcc -E a.c

//结果

# 2 "a.c" 2

enum ST
{
A,
B,
C,
D
};

void main()
{
int e = 4; //预编译后被替换

int a = A; //预编译后没有被替换
}

可以看出,#define 定义的常量,在预编译的时候做了替换,而enum定义的常量,并不是在预编译的时候进行替换,只是在运行的时候,根据标识去常量区获取对应的值。

1
泥瓦匠 267天前

enum结构体定义都是一些常量值,放在静态常量存储区。类似于类里面声明为static const的常量。
class A {
public:
enum Type{
Cat = 0,
Dog,
Hourse,
Cow
};
static const int i = 3;
};
cout << sizeof(A) <<endl; 
输出是1。

 
  1. enum Type{
  2. Cat = 0,
  3. Dog,
  4. Hourse,
  5. Cow = 0xffffff
  6. };
  7. enum TypeChar : unsigned char {
  8. A = 0x00,
  9. B,
  10. C = 0xff
  11. };
  12. struct A {
  13. Type t;
  14. TypeChar tc;
  15. };
  16. int main() {
  17. cout << sizeof(Type) << endl;
  18. cout << sizeof(TypeChar) << endl;
  19. cout << sizeof(A) << endl;
  20. Type t1;
  21. TypeChar tc;
  22. Type t2;
  23. cout << &t1 << endl;
  24. cout << &tc << endl;
  25. cout << &t2 << endl;
  26. cout << sizeof(t1) << endl;
  27. return 0;
  28. }

输出是:


枚举默认是用int类型来存储的,32位系统下占4个字节。可以存储的最大值是0xffffff。 你可以改变枚举的大小例如enum TypeChar : unsigned char{} 这样可以节省空间, 在嵌入式编程中较为常见。嵌入式编程中,甚至有用位来存储的。

 
  • 问也

  • QQ群: 58485477
  • Email: 1843610564@qq.com
Copyright © 2013-2014 问也. 当前呈现版本 1.3.6 
京ICP备14003849号-1
 

@清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?的更多相关文章

  1. vs中调试程序查看变量在内存中的内容的方法

    vs中调试程序 查看变量在内存中的内容的方法 https://blog.csdn.net/guojg1988/article/details/42922149 原文链接:http://www.sows ...

  2. Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(例如顺序:1、初始化spring容器,2、初始化线程池,3、加载业务代码,将数据库中数据加载到内存中)

    最近公司要做功能迁移,原来的后台使用的Netty,现在要迁移到在uap上,也就是说所有后台的代码不能通过netty写的加载顺序加载了. 问题就来了,怎样让迁移到tomcat的代码按照原来的加载顺序进行 ...

  3. C/C++中整数与浮点数在内存中的表示方式

    在C/C++中数字类型主要有整数与浮点数两种类型,在32位机器中整型占4字节,浮点数分为float,double两种类型,其中float占4字节,而double占8字节.下面来说明它们在内存中的具体表 ...

  4. java中的各种数据类型在内存中存储的方式

    原文地址:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8251456 1.Java是如何管理内存的 java的内存管理就是对象的分配和释放问 ...

  5. javascript中的链表结构—从链表中删除元素

    1.概念 上一个博文我们讲到链表,其中有一个方法remove()是暂时注释的,这个方法有点复杂,需要添加一个Previous()方法找到要删除的元素的前一个节点,这一个博文我们来分析一下这个remov ...

  6. JVM中java实例对象在内存中的布局

    普通的Java对象实例 和  Java数组实例.Java数组实例的对象头多了一个数组的长度.Java虚拟机可以通过普通java对象的元数据来确定java对象的大小,但是从数组的元数据中却无法确定数组的 ...

  7. MFC中的NMHDR结构体和NMUPDOWN结构体

    建立spin控件,创建UDN_DELTAPOS一个消息函数后: void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult) { NM ...

  8. Java 数组在内存中的结构

    Java中的数组存储两类事物: 原始值(int,char,...),或者引用(对象指针). 当一个对象通过 new 创建,那么将在堆内存中分配一段空间,并且返回其引用(指针). 对于数组,也是同样的方 ...

  9. Java中内存中的Heap、Stack与程序运行的关系

    堆和栈的内存管理 栈的内存管理是顺序分配的,而且定长,不存在内存回收问题:而堆 则是随机分配内存,不定长度,存在内存分配和回收的问题:堆内存和栈内存的区别可以用如下的比喻来看出:使用堆内存就象是自己动 ...

随机推荐

  1. 深入解析Vue.js中v-bind v-model的使用和区别

    v-model 指令在表单控件元素上创建双向数据绑定,所谓双向绑定,指的就是我们在js中的vue实例中的data与其渲染的dom元素上的内容保持一致,两者无论谁被改变,另一方也会相应的更新为相同的数据 ...

  2. Codeforces 1209E2. Rotate Columns (hard version)

    传送门 发现 $n$ 很小,考虑状压 $dp$,但是如果强行枚举列并枚举置换再转移复杂度太高了 考虑推推结论,发现我们只要保留列最大值最大的 $n$ 列即可,证明好像挺显然: 假设我们让列最大值比较小 ...

  3. 下载MySQL的rpm包安装MySQL

    cd /usr/local/src wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-community-server-5.7.27-1.el ...

  4. sql server 幂运算函数power(x,y)、square(x)、exp(x)

    --POWER(x,y)函数返回x的y次乘方的结果值 --SQUARE(x)函数返回指定浮点值x的平方 --EXP(x)函数返回e的x乘方后的值 示例:select POWER(2,2), POWER ...

  5. Linux操作系统笔记

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> //linux下面的头文件 #include ...

  6. 引用vector里的元素被删除后,引用会怎么样?

    引用的定义不多说,直接看做变量的别名就可以了.有一天写着写着代码,突然想到,如果对vector里某个元素设置引用后,将这个元素从vector里删除会怎么样?我思考了下,认为那个元素会被删除,但是引用还 ...

  7. Linux 安装 nginx 安装PCRE库

    PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库.这些在执行正规表达式模式匹配时用与Perl 5同样的语法和语义是 ...

  8. error: ‘ostream_iterator’ was not declared in this scope

    在代码中添加      #include <iterator>

  9. VMware虚拟机中的CentOS7安装Nginx后本机无法访问的解决办法

    VMware虚拟机中的CentOS7安装Nginx后本机无法访问的解决办法 在linux上安装nginx 请参考:Linux Centos7 安装 nginx 在虚拟机centos7上安装nginx之 ...

  10. python中字符串格式化的两种方法

    知识点汇总;1-字符串格式化输出方法一: % 1-print('名字是 %s,年龄是%s' % (name ,age)) 2- %s ---字符串-----相当于执行了str() 3- (name , ...