【问题标题】:How to use switch with extern constants?如何使用带有外部常量的开关?
【发布时间】:2011-04-07 09:40:37
【问题描述】:

一些code.cpp文件包含

extern const int v1;
extern const int v2;
extern const int v3;
extern const int v4;

int _tmain(int argc, _TCHAR* argv[])
{
    int aee = v1;
    switch (aee)
    {
    case v1:
        break;
    case v2:
        break;
    case v3:
        break;
    case v4:
        break;
    }
        return
}

另一个文件定义.cpp包含

const int v1 = 1;
const int v2 = 2;
const int v3 = 3;
const int v4 = 4;

编译时出现错误 C2051: case expression not constant 但是,当我删除 extern 时,一切都很好。

有没有办法让它与 extern 一起工作?

【问题讨论】:

  • 你想用这个达到什么目的?
  • 不用extern也能编译吗?重定义不是会报错吗?
  • 实际上这是在框架深处以更复杂的方式使用的。我的目标是在更改某些头文件时避免重新编译某些主要部分代码
  • 嗯,有点腥味!!如果您需要采用这种方法,那么肯定会有更好的方法(映射、if-else、继承——随便,不是这样的低级 hack)——我的 2c。
  • @hype:常量默认有内部链接,所以如果你在这里删除extern,你不会得到“多重定义”错误。不过,它们的值都为零。

标签: c++ constants switch-statement extern


【解决方案1】:

没有。 switch 仅适用于完全定义的整数类型常量(包括明确转换为整数类型的枚举成员和类)。 here 是 MSDN 旧参考的链接,但内容仍然有效。

我在对另一个答案的评论中提供的

This link 解释了编译器可以对汇编代码执行哪些优化。如果这延迟到链接步骤,这将是不可能的。

因此,在您的情况下,您应该使用if..else if

【讨论】:

    【解决方案2】:

    Switch 语句要求在编译时知道 case 值。

    删除extern 时它似乎起作用的原因是您定义了一个常量零。

    【讨论】:

    • @Romeno:我想switch语句的目的是生成不进行比较的汇编代码,而是根据一个值直接跳转到一条指令。因此汇编代码应该在编译时完全生成。请参阅this link,它似乎涵盖了该主题。
    • 因为编译器必须为 switch case 生成分支表,在运行时它会使用它来识别在给定特定值的情况下应该跳转到哪个地址
    • 标准要求:“每个case标签的表达式必须是一个整数常量表达式并且同一switch语句中的两个case常量表达式不能有相同的值 转换后”。如果表达式不是编译时常量,编译器就无法判断是否满足这些约束。编译器的任务之一是断言程序是格式良好的。链接器不在乎,它只需要将编译器抛出的内容生成一个二进制文件,并且它依赖于编译器不会对它撒谎。
    • @Romeno:链接器无法管理此任务的原因很简单,这不是它的业务。程序员有一个想法,并通过定义明确的语言在源代码中表达它。前端(编译器是其中的一部分)读取源代码,验证语法是否有效,并将(依赖于实现的)语义表示交给后端(汇编器和链接器所属的)。后端的唯一任务是将这个“概念”转化为二进制形式,可以在目标 CPU 上运行(并且可以在不改变语义的情况下选择性地去除多余的东西)。
    • @James Kanze:不过,这是有道理的。如果您查看像 gcc 这样的编译器,它有十几个前端和十几个后端(或两打?),那么很明显,不让链接器关心查看源代码中的任何信息是多么巧妙。同一个链接器将从 C、C++、Go 或 Fortran 生成二进制文件,它甚至不知道。同一个编译器将解析在 i86、MIPS、68k 等上运行的 C++,它也不知道。现在最近,随着 LTO 的出现,我想知道这仍然是如何工作的,但显然它确实......
    猜你喜欢
    • 2018-07-27
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多