C++ 中的 enum 结构在内存中是怎么存储的?里面存储的是常量值吗?
关于占用内存的大小,enum类型本身是不占内存的,编译器直接替换。但是enum类型的变量肯定是占内存的(关于占用内存的大小,看后面详述)。
enum需要特别注意的是它的取值范围和类型分配。
关于确定enum的取值范围,如果一个enum中所有的枚举值非负,那么枚举的表示范围是[0,2^k - 1],其中2^k是使得所有枚举值位于此范围内的最小的2的幂。如果是有负值,那么范围就是[-2^k,2^k-1]。因此对一个给定的整数值,如果使用强制转换,而其值又不在枚举的表示范围以内,其行为是未定义的。
举一个例子:
- enum EnumTest{
- a =1,b = 5};
其中没有负数,最大值是5,二进制表示是101,需要3bits能够容纳下。因此取值范围是[0,7]。
- enum EnumTest{
- a =-2,b = 5};
绝对值最大的是5,需要3bits能够容纳下,但是因为有负值,需要增加一个符号位,于是需要4bits,取值范围是[-8,7]。
C++规定枚举的大小只要能够容纳下3bits或者4bits(上面的例子)就行,至于分配1byte还是4bytes,是编译器决定的,但是C++标准有个限制:1<=sizeof(enum)<=sizeof(int)。
实例代码:
- #include <iostream>
- using namespace std;
- class A{
- public:
- //enum类型本身不占内存
- enum EnumTest{
- a =1,b = 5};
- };
- enum EnumTest{
- a =1,b = 5};
- class B{
- public:
- private:
- //enum理想的变量会占用内存
- enum EnumTest enumSample1;
- };
- int main()
- {
- enum EnumTest{
- a =1,b = 5};
- cout << sizeof(enum EnumTest) << endl;
- //注意:此处结果是未定义的
- enum EnumTest enumSample1 = (enum EnumTest)10;
- cout << enumSample1 << endl;
- cout << "sizeof(Class A) = " << sizeof(A) << endl;
- cout << "sizeof(Class B) = " << sizeof(B) << endl;
- return 0;
- }
运行结果:
最后,给你提供好的参考资料:
what is the size of an enum type data in C++?
个人觉得谈论enum的内存分布没有太大的意义,因为enum中的值是在编译阶段就确定了。
虽然我们可以写出如下的代码:
- enum DefType{
- a = 1,
- b = 5
- };
- DefType testDefType; // 创建一个enum DefType的变量
但若像结构体一样调用testDefType.a,则不能通过编译。
若我们在函数外写下如下的语句:
- enum DefType{
- a = 1,
- b = 5
- };
- enum DefType2{
- a = 10,
- b2 = 50
- };
这样编译不会通过:error C2365: “a”: 重定义;以前的定义是“枚举数”。
关于enum的语法细节,楼上几位已经说的很详细了,不在赘述,只是举个enum常用的例子。
- class AA{
- enum DefType{
- a = 10,
- b = 5
- };
- int arr[a];
- };
- class BB{
- enum DefType2{
- a = 100,
- b2 = 50
- };
- int arr[a];
- };
这也是在类中静态声明一个数组的好方法称为enum hack。
@卢俊的答案说对了一半,宏虽然是在预处理阶段做了替换,但enum值不是在运行时确定,而是在编译时确定,从生成的汇编代码可以证明:
- ; 16 : int e = E;
- mov DWORD PTR _e$[ebp], 4
- ; 17 :
- ; 18 : int a = A;
- mov DWORD PTR _a$[ebp], 0
补充: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定义的常量,并不是在预编译的时候进行替换,只是在运行的时候,根据标识去常量区获取对应的值。
enum结构体定义都是一些常量值,放在静态常量存储区。类似于类里面声明为static const的常量。
class A {
public:
enum Type{
Cat = 0,
Dog,
Hourse,
Cow
};
static const int i = 3;
};
cout << sizeof(A) <<endl;
输出是1。
- enum Type{
- Cat = 0,
- Dog,
- Hourse,
- Cow = 0xffffff
- };
- enum TypeChar : unsigned char {
- A = 0x00,
- B,
- C = 0xff
- };
- struct A {
- Type t;
- TypeChar tc;
- };
- int main() {
- cout << sizeof(Type) << endl;
- cout << sizeof(TypeChar) << endl;
- cout << sizeof(A) << endl;
- Type t1;
- TypeChar tc;
- Type t2;
- cout << &t1 << endl;
- cout << &tc << endl;
- cout << &t2 << endl;
- cout << sizeof(t1) << endl;
- return 0;
- }
输出是:
枚举默认是用int类型来存储的,32位系统下占4个字节。可以存储的最大值是0xffffff。 你可以改变枚举的大小例如enum TypeChar : unsigned char{} 这样可以节省空间, 在嵌入式编程中较为常见。嵌入式编程中,甚至有用位来存储的。
@清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?的更多相关文章
-
vs中调试程序查看变量在内存中的内容的方法
vs中调试程序 查看变量在内存中的内容的方法 https://blog.csdn.net/guojg1988/article/details/42922149 原文链接:http://www.sows ...
-
Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(例如顺序:1、初始化spring容器,2、初始化线程池,3、加载业务代码,将数据库中数据加载到内存中)
最近公司要做功能迁移,原来的后台使用的Netty,现在要迁移到在uap上,也就是说所有后台的代码不能通过netty写的加载顺序加载了. 问题就来了,怎样让迁移到tomcat的代码按照原来的加载顺序进行 ...
-
C/C++中整数与浮点数在内存中的表示方式
在C/C++中数字类型主要有整数与浮点数两种类型,在32位机器中整型占4字节,浮点数分为float,double两种类型,其中float占4字节,而double占8字节.下面来说明它们在内存中的具体表 ...
-
java中的各种数据类型在内存中存储的方式
原文地址:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8251456 1.Java是如何管理内存的 java的内存管理就是对象的分配和释放问 ...
-
javascript中的链表结构—从链表中删除元素
1.概念 上一个博文我们讲到链表,其中有一个方法remove()是暂时注释的,这个方法有点复杂,需要添加一个Previous()方法找到要删除的元素的前一个节点,这一个博文我们来分析一下这个remov ...
-
JVM中java实例对象在内存中的布局
普通的Java对象实例 和 Java数组实例.Java数组实例的对象头多了一个数组的长度.Java虚拟机可以通过普通java对象的元数据来确定java对象的大小,但是从数组的元数据中却无法确定数组的 ...
-
MFC中的NMHDR结构体和NMUPDOWN结构体
建立spin控件,创建UDN_DELTAPOS一个消息函数后: void CSpinDlg::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult) { NM ...
-
Java 数组在内存中的结构
Java中的数组存储两类事物: 原始值(int,char,...),或者引用(对象指针). 当一个对象通过 new 创建,那么将在堆内存中分配一段空间,并且返回其引用(指针). 对于数组,也是同样的方 ...
-
Java中内存中的Heap、Stack与程序运行的关系
堆和栈的内存管理 栈的内存管理是顺序分配的,而且定长,不存在内存回收问题:而堆 则是随机分配内存,不定长度,存在内存分配和回收的问题:堆内存和栈内存的区别可以用如下的比喻来看出:使用堆内存就象是自己动 ...
随机推荐
-
Mybatis框架 的快速入门
MyBatis 简介 什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果 ...
-
Android国际化--I18N
在res下创建对应国家的环境的目录如:values-zh,values-en,然后在对应的目录下将对应的字符串翻译成对应国家的语言即可.
-
python核心编程-第五章-习题
1.长整型表示数的范围比整型更大.在python中,整型.长整型趋于统一,普通用户不用特别关注两者区别,仅当需引用C语言时需要特别注意. 2.操作符 (a) def product(x,y): ret ...
-
windows程序员进阶系列:《软件调试》之Win32堆的调试支持
Win32堆的调试支持 为了帮助程序员及时发现堆中的问题,堆管理器提供了以下功能来辅助调试. 1:堆尾检查(Heap Tail Check) HTC,在堆尾添加额外的标记信息,用于检测堆块是否溢出. ...
-
C#基础随手笔记之基础操作优化
对数据的查询,删除等基本操作是任何编程语言都会涉及到的基础,因此,研究了一下C#中比较常用的数据操作类型,并顺手做个笔记. List查询时,若是处理比较大的数据则使用HashSet<T>类 ...
-
从壹开始前后端分离 41 || Nginx+Github+PM2 快速部署项目(一)
前言 哈喽大家周一好!今天是农历腊月二十三,小年开始,恭祝大家新年快乐(哈哈你五福了么
-
c3.cpp
Char16_t(在字符串前加u)和char32_t(在字符串前加U)都是无符号的,数字代表长度(底层长度随系统而定) 在函数bool中,任何非0值都代表真(即使他是个负数),只有0代表false 一 ...
-
P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)
P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...
-
Chip Factory(01字典树)
Chip Factory http://acm.hdu.edu.cn/showproblem.php?pid=5536 Time Limit: 18000/9000 MS (Java/Others) ...
-
PHP 常用函数总结(四)
9.PHP常用判断函数 is_bool();//判断是否为布尔型 is_float(); //判断是否为浮点型 is_int(); //判断是否为整型 is_numeric(); //判断是否为数值型 ...