【问题标题】:Enums in computer memory计算机内存中的枚举
【发布时间】:2016-02-03 23:38:55
【问题描述】:

引用维基百科关于enumerated types 的文章将是这个问题的最佳开场白:

换句话说,枚举类型具有彼此不同的值,并且可以比较和分配,但程序员未指定 具有任何特定的具体计算机内存中的表示;编译器和解释器可以任意表示它们。

虽然我了解枚举的定义和用途,但我还不能掌握枚举和内存之间的交互——当声明枚举类型而不创建枚举类型变量的实例时,是类型定义作为联合还是结构存储在内存中?前面提到的 Wiki 摘录背后的含义是什么?

【问题讨论】:

  • 我对枚举的看法是它们只存在于编译时间之前(无论如何在 c 中)。即它们在编译时替换为它们的整数值
  • 表示和实现在不同的编程语言中可能会有很大的不同。当您询问 C 时,请阅读 C enums。
  • 基本上是说如果你有一个枚举变量,编译器可以选择任何适合其需要的底层基本类型在内存中表示它。给定enum Xyz { ABC, DEF, GHI };,C 程序员(实际上是一般程序员)无法控制用于存储enum Xyz 值的内存类型。在 C 语言中,它可以是 charshortint 或编译器随意选择的其他类型——当然,除非有一个 ABI(应用程序二进制接口)定义了编译器必须做什么。
  • 还有一个声明 从不分配内存。不要将其与定义混淆
  • 在不创建变量的情况下,诸如 ABC 之类的值可能只是汇编指令的一部分,或者它可能存储在某个地方——可能在文本段中,因为它的值在程序运行时不会改变.

标签: enums language-agnostic


【解决方案1】:

维基百科的摘录并没有专门讨论 C 的 enum 类型。 C 标准对enums 的工作方式有一些特定要求。

枚举类型与char 或某些有符号或无符号整数类型兼容。表示的选择取决于编译器,它必须记录其选择(它是实现定义的),但类型必须能够表示枚举的所有值。

枚举常量的值默认从0开始,每个后续常量递增1

enum foo {
    zero, // equal to 0
    one,  // equal to 1
    two   // equal to 2
};

常量总是int 类型,不管enum 类型本身与什么兼容。 (将常量设为枚举类型会更有意义;出于历史原因,它们的类型为 int。)

您可以为部分或全部常量指定值——这意味着这些值不一定是不同的:

enum bar {
    two = 2,
    deux = 2,
    zwei = 2,
    one = 1,
    dos  // implicitly equal to 2
};

定义枚举类型不会导致在运行时将任何内容存储在内存中。如果定义枚举类型的对象,该对象的值将存储在内存中(除非它被优化掉),并将占用sizeof (enum whatever) 字节。这与任何其他类型的对象相同。

枚举常量被视为常量表达式。表达式two 的处理方式几乎与常量2 相同。

请注意,C++ 对enum 类型有一些不同的规则。你的问题被标记为 C,所以我不会详细说明。

【讨论】:

  • 很好的答案 - 谢谢!然而,我在两个地方感到困惑。首先,您提到枚举类型由编译器表示为“char”、“uint”或其他,具体取决于编译器的设置。 'char' 值的可能值比无符号整数要少,所以将'enum' 对象默认为'uint' 或者如果'chars' 填满编译器会自动执行它不是更实用吗?其次,如果枚举常量本身是“枚举”类型,这是否意味着这些常量中的每一个都将具有它可以采用的值范围?只是范围更小?
  • @Agrus :我不确定您所说的 uint 是什么意思;没有这样的标准类型。 enum 类型可以与char 具有相同的表示形式,可以是任何有符号整数类型,也可以是任何无符号整数类型。编译器可以以它喜欢的任何方式做出选择。至于枚举常量,一个常量只有一个固定值,而不是一个值的范围。
  • 也许uint 是嵌入式系统编程更常见的东西。但是,您是对的,uint 不是标准类型,也许它是为了简单起见。如果enum 没有被赋值,那么编译器会自行决定分配给它的类型,是char 还是int,对吧?如果程序员没有指定值,那么它们从 0 开始。那么如果定义的枚举常量的数量大于可用的chars 的数量会发生什么?这纯粹是假设,因为枚举似乎相当短。
  • @Agrus:uint 通常是unsigned int 的别名(typedef)。我宁愿只写unsigned int,这样就没有歧义了。但是enum 类型可以与 any 有符号或无符号类型兼容,或者与普通的 char 兼容;在这种情况下,uintunsigned int 没有什么特别之处。每个枚举常量的值由语言指定,而不是由编译器指定;它是指定的值,否则0 为第一个或前一个值 + 1。编译器选择底层类型,但该类型必须能够表示所有常量的值。
  • @Agrus:如果某些常量不适合char,编译器必须选择更宽的类型。
【解决方案2】:

这意味着枚举常量不需要位于内存中。您不能获取他们的地址。

这允许编译器将所有对枚举常量的引用替换为它们的实际值。例如代码:

enum { x = 123; }
int y = x;

可以像这样编译:

int y = 123;

当声明枚举类型而不创建枚举类型变量的实例时,类型定义是作为联合还是结构存储在内存中的?

在 C 中,类型主要是编译时构造;一旦程序被编译成机器码,所有的类型信息都会消失*。访问结构成员是“访问该指针后 n 个字节的内存”。

因此,如果编译器如上所示内联所有枚举,那么枚举在编译后的代码中根本不存在。

* 调试信息部分除外,但通常只能由调试器读取。

【讨论】:

  • 感谢您的回复!这是否意味着如果'x'在代码中'y'之前被声明为变量,那么用'x'的值分配'y'(即y = x),将使用'x'的地址被放置在内存中,并在到达该指令时复制该地址的任何内容?
猜你喜欢
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多