【问题标题】:How compiler handles symbolic constants in enumerations?编译器如何处理枚举中的符号常量?
【发布时间】:2020-10-05 12:14:36
【问题描述】:

如果我们谈论宏而不是编译器在预处理阶段处理它们,那么枚举器呢?编译器如何看待它们。例如看下面的代码:

#include <stdio.h> 
enum day {sunday = 1, monday, tuesday = 5, 
        wednesday, thursday = 10, friday, saturday}; 

int main() 
{ 
    printf("%d %d %d %d %d %d %d", sunday, monday, tuesday, 
            wednesday, thursday, friday, saturday); 
    return 0; 
} 

在这个特定的示例中,我什至没有为枚举数据类型创建任何变量。我只是在我的printf() 语句中使用enumeration-constants。枚举器内部的工作方式与宏类似吗?在预处理过程中,所有这些符号常量会被整数常量替换吗?编译器究竟是如何处理它们的?

【问题讨论】:

  • 仅供参考:enum 相关内容不会被预处理器以任何方式更改(除非您使用常规宏)
  • 相关C11 6.7.2.2

标签: c enums macros constants enumeration


【解决方案1】:

枚举器在内部的工作方式是否类似于宏?

有点是,有点不是。

所有这些 符号常量被替换为整数常量 预处理?

没有。除了预处理指令、defined 运算符和定义的宏名称之外,预处理器不知道一个标识符与另一个标识符。你可以试试这个:

#include <stdio.h>

#define MACRO_TRUE 1
enum bool_enum { ENUM_FALSE = 0, ENUM_TRUE = 1 };

int main(void) {
#if MACRO_TRUE
    puts("Macro identifiers are known to the preprocessor.");
#else
    puts("Macro identifiers are not known to the preprocessor.");
#endif
#if ENUM_TRUE
    puts("Enum constants are known to the preprocessor.");
#else
    puts("Enum constants are not known to the preprocessor.");
#endif
}

输出应该是

Macro identifiers are known to the preprocessor.
Enum constants are not known to the preprocessor.

编译器究竟是如何处理它们的?

范围内的枚举常量类似于其他整数常量,例如42,除了上面的警告,它们不会被预处理器解释为这样。它们可以用在整数常量表达式中,例如,在switch 语句中的case 标签中,它们是各种用途所必需的。该标准没有指定详细信息,但大多数编译器将它们与宏类似地对待,因为在可执行文件中没有为它们保留存储空间——源代码被视为枚举常量被替换为它们出现在表达式中的相应整数值,经过预处理。当然,它们不能识别对象,因为它们不是 &amp; 运算符的可接受操作数。

这要与const 限定变量的行为区分开来。这些标识实际对象,而不仅仅是常量。它们可能不会在常量表达式中使用,并且它们确实有与之关联的存储(至少在抽象机中),因此它们的地址可以通过&amp; 运算符获得。

【讨论】:

  • 您的回答几乎解决了所有问题,但仍然存在一个基本疑问。我无法理解它是否以某种方式在内部被视为const 变量,而不是为什么它们没有与之关联的存储。也与此无关,但您能告诉我们为什么我们不能在 switch 案例中使用const 变量,但我们可以使用enums 轻松地这样做吗?
  • @LocalHost,枚举常量被 not 视为const 变量,正如这个答案已经说过的那样。 const-qualified 变量与“常量”不同。您所询问的细节——是否有关联的存储,它们是否可用于形成“常量表达式”——是这种区别的直接后果。语言规范说常量(包括枚举常量)可能出现在常量表达式中,而对象标识符可能不会出现,尽管有const 限定。
【解决方案2】:

不,它们不像宏那样工作,而是像 const 变量那样工作。

所以你的代码大致相当于这个:

#include <stdio.h> 

const int sunday = 1, monday = 2, tuesday = 5, 
        wednesday = 6, thursday = 10, friday = 11, saturday = 12; 

int main() 
{ 
    printf("%d %d %d %d %d %d %d", sunday, monday, tuesday, 
            wednesday, thursday, friday, saturday); 
    return 0; 
}

在这里查看:https://www.godbolt.org/z/cErv5W

【讨论】:

  • ... 除了enum foo { sunday = 1 };const int tuesday = 5; 中的主要例外,第一个是编译时常量,第二个不是。 switch (bar) { case sunday: /*ok*/; case tuesday: /*nope -- compiler error*/; }
  • @pmg 是的,当然,我将大致改为非常粗略
  • @Jabberwocky,问题不在于“大致”,而是const int“常量”类型的调用对象。
【解决方案3】:

不,枚举在内部不像宏那样工作,枚举是一种在编译期间被评估的数据类型,而宏被预处理器复制为文本。

来自 gcc gnu 文档: 宏是已命名的代码片段。无论何时使用该名称,它都会被宏的内容所取代。有两种宏。它们的主要区别在于使用时的外观。类对象宏在使用时类似于数据对象,类函数宏类似于函数调用。

枚举是 C 语言中用户定义的数据类型。它用于为整数常量分配名称,使程序易于阅读和维护。关键字“enum”用于声明枚举。

【讨论】:

  • 您关注的是enum types,但问题是关于枚举constants。这些和类对象宏之间确实有一些相似之处,也有一些不同之处。这个答案几乎没有解决这些问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多