【问题标题】:why compiler restricts global variable always to be initialized by constant value? [duplicate]为什么编译器限制全局变量总是由常量值初始化? [复制]
【发布时间】:2013-10-08 10:44:05
【问题描述】:

让我举例说明,

int a = 100;
int b = a;

int main(int argc, char **argv, char ** env)
{
  printf("The value of b=%d\r\n",b);

  return 0;
}

现在,我得到了预期的编译错误。

[joshis1@localhost global_var]$ gcc global_var.c -o global_var.out
global_var.c:4:1: error: initializer element is not constant
 int b = a;
 ^

我想在这里学习的是为什么我会收到错误消息?为什么编译器限制此操作。 我了解初始化的全局变量存储在数据段中。编译器可以首先解析 a 的值,然后将相同的值赋给 b。为什么它缺少这个功能?编译器做起来复杂吗?此功能背后是否有任何理由或只是 C 的一个陷阱?

【问题讨论】:

  • 错误信息就是你的答案。
  • 那么,编译器应该如何在函数外部运行可执行代码(计算表达式)? C++ 编译器可以做到这一点,但这通常是通过创建一些在 main() 之前运行的辅助函数来工作的,这是丑陋的、hackish、隐式和隐藏的,所以你的程序并没有真正按照你的想法去做,而 C 程序员不喜欢那样。 (C++ 程序员会这样做。)
  • 编译器是编译器而不是解释器
  • @GrijeshChauhan 不适用。 OP 知道他为什么会出错,他正在寻找其背后的设计决策。
  • @H2CO3 评估初始化程序的值,并将其作为 b 的初始化程序存储在数据中 - 我相信这就是 Joshi 想要的。但是有些东西阻止了这一点(我很高兴它是)。运行时评估是不可能的。我已经摆脱了这些烦人且严重的误解。

标签: c


【解决方案1】:

C 可以移植到非常简单的小型机器上。计算非常量表达式需要函数中的运行时代码。在嵌入式编程中,您可能不需要任何未明确编程的函数(或代码)。

如果配置了不同的选项,您的编译器可能会将初始化程序评估为语言扩展。如果失败了,您可以尝试 C++(甚至只是类似 C 的子集)或其他可以做更多您喜欢的事情的语言 :v)。

【讨论】:

    【解决方案2】:

    官方文档,取自line 1644, 6.7.8 Initialization,说:

    具有静态存储持续时间的对象的初始化程序中的所有表达式都应为常量表达式或字符串字面量。

    为什么存在规则是一个更困难的问题 - 也许正如您所建议的那样,编译器很难做到。在 C++ 中,这样的表达式是有效的,但全局初始化器可能会调用构造函数等,而对于 C,为了保持紧凑,全局变量在编译阶段进行评估。 int b = a; 在编译时是可评估的,但 int b = a + c; 呢? int b = pow(a, 2);?你会在哪里停下来? C 决定不让你开始是最好的解决方案。

    【讨论】:

    • 编译器要做的不仅仅是“难”。它涉及停机问题。如果静态初始化不是常量,那么在编译时评估它们将需要解释已解析的代码,这可能不会终止。另一方面,如果静态初始化不是常量,而是在运行时确定的,那么您将需要一个非常复杂的机制来检测和排序所有静态初始化。 C++ 接近这一点,但它远非简单。基本上不保证初始化块之间的顺序。
    • @EdwinBuck:当然,这是一个不断重复的虚构问题,就像它是自然法则一样。没有人期望编译器在给出错误代码的情况下终止。这从来都不是问题。尝试给 C++ 编译器一些有用的元程序,看看会发生什么。另一方面,如果它可以解释命令式 C++ 而不是解释难以使用的函数式元语言,那么它将在毫秒内完成,而使用的堆数量可以忽略不计。有时,完全和完全的实用胜过一些理论上的纯洁性。
    • @KubaOber 停机问题远非想象。编译器预计会终止,但如果需要真正的解释,编译器很容易失败:#define a b+1#define b a+1。唯一需要想象力的部分是想象如何以有趣的方式滥用它。
    【解决方案3】:

    来自您的评论:

    ...如何强制编译器完成这项工作?

    好吧,你不能让编译器接受你所拥有的,但你可以通过定义你想要分配给两个变量的值来实现你的目标。

    #define INITIAL_VALUE_FOR_A 100
    
    int a = INITIAL_VALUE_FOR_A;
    int b = INITIAL_VALUE_FOR_A;
    

    现在如果需要更改初始值,只需在一处更改即可;

    【讨论】:

    • 对不起,这不是我要找的。​​span>
    • @SHREYASJOSHI 如果您对“您不能;语言禁止这样做”不满意,那么您使用了错误的语言。想想等式的哪一部分在你的控制之下。
    【解决方案4】:

    其他人已经说明了为什么通常不能允许初始化器是任意表达式。

    强制编译器接受代码”的方法是更改代码。执行文件范围、外部链接(vulgo:“全局”)变量的任意初始化的规范方法是在 main() 的开头调用一个初始化函数,该函数按您需要的顺序执行所有初始化:

    #include <stdio.h>
    int a;
    int b;
    
    void init(void)
    {
         a = 100;
         b = a;
    }
    
    int main(int argc, char **argv)
    {
         init();
         printf("The value of b=%d\n", b);
    
         return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-12
      相关资源
      最近更新 更多