zoukankan      html  css  js  c++  java
  • @清晰掉 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.  
    3. using namespace std;
    4.  
    5. class A{
    6. public:
    7.  
    8. //enum类型本身不占内存
    9. enum EnumTest{
    10. a =1,b = 5};
    11. };
    12.  
    13. enum EnumTest{
    14. a =1,b = 5};
    15.  
    16. class B{
    17. public:
    18.  
    19. private:
    20. //enum理想的变量会占用内存
    21. enum EnumTest enumSample1;
    22. };
    23.  
    24. int main()
    25. {
    26. enum EnumTest{
    27. a =1,b = 5};
    28.  
    29. cout << sizeof(enum EnumTest) << endl;
    30.  
    31. //注意:此处结果是未定义的
    32. enum EnumTest enumSample1 = (enum EnumTest)10;
    33.  
    34. cout << enumSample1 << endl;
    35.  
    36. cout << "sizeof(Class A) = " << sizeof(A) << endl;
    37. cout << "sizeof(Class B) = " << sizeof(B) << endl;
    38.  
    39. return 0;
    40. }

    运行结果:

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

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

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

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

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

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

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

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

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

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

      
    1. ; 16 : int e = E;
    2.  
    3. mov DWORD PTR _e$[ebp], 4
    4.  
    5. ; 17 :
    6. ; 18 : int a = A;
    7.  
    8. 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。

      
    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.  
    13. struct A {
    14. Type t;
    15. TypeChar tc;
    16. };
    17. int main() {
    18. cout << sizeof(Type) << endl;
    19. cout << sizeof(TypeChar) << endl;
    20. cout << sizeof(A) << endl;
    21. Type t1;
    22. TypeChar tc;
    23. Type t2;
    24. cout << &t1 << endl;
    25. cout << &tc << endl;
    26. cout << &t2 << endl;
    27. cout << sizeof(t1) << endl;
    28. return 0;
    29. }

    输出是:

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

  • 相关阅读:
    API下载文件
    c# 测试网络连接
    C# Word 插入签名图片
    c# word文档合并
    c# 文件筛选
    e
    基本初等函数(Basic elementary function)
    前端性能优化学习
    解决点击穿透的最佳实践
    ObjectARX通过选定的实体获取所有组名示例
  • 原文地址:https://www.cnblogs.com/ysdu/p/4690090.html
Copyright © 2011-2022 走看看