为什么编译器限制全局变量始终用常量值初始化? [重复]

时间:2021-02-06 01:44:06

This question already has an answer here:

这个问题在这里已有答案:

Let me exemplify this,

让我举例说明一下,

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;
}

Now, I get the compilation error as expected.

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

[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;
 ^

What I want to learn here is why do I get the error? why compiler restricts this operation. I understand that initialized global variables are stored in Data segments. The compiler could have first resolved the value of a,and then could have assigned the same value to b. Why it lacks this feature? Is it complex for compiler to do? Is there any rationale behind this functionality or just a pitfall of C?

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

4 个解决方案

#1


11  

The official documentation, taken from line 1644, 6.7.8 Initialization, says:

官方文档取自1644行,6.7.8初始化,说:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

具有静态存储持续时间的对象的初始值设定项中的所有表达式应为常量表达式或字符串文字。

Why the rule exists is a more difficult question - perhaps as you suggest it is difficult for the compiler to do. In C++ such an expression is valid, but global initialiser may invoke constructors, etc, whereas for C, to keep things compact, globals are evaluated at the compile phase. int b = a; is evaluable at compile time, but what about int b = a + c;? int b = pow(a, 2);? Where would you stop? C decides that not allowing you to start is the best solution.

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

#2


4  

From your comment:

从你的评论:

...how can I force compiler to make this work?

...我如何强制编译器使其工作?

Well you can't make the compiler accept what you have but you can accomplish your goal by defining the value you want to assign to both variables.

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

#define INITIAL_VALUE_FOR_A 100

int a = INITIAL_VALUE_FOR_A;
int b = INITIAL_VALUE_FOR_A;

Now if you need to change the initial value, you only need to change it in one place;

现在,如果您需要更改初始值,您只需要在一个地方更改它;

#3


1  

C is portable to very simple, small machines. Evaluating expressions that aren't constant requires runtime code, in a function. In embedded programming you might not want any functions (or code) that you did not explicitly program.

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

Your compiler probably will evaluate the initializer as a language extension, if configured with different options. If that fails, you could try C++ (even just the C-like subset) or another language that does more things you like :v) .

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

#4


0  

Others have stated why initializers in general can't be allowed to be arbitrary expressions.

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

The way to "force the compiler to accept the code" is to change the code. The canonical way to perform arbitrary initialization of file scope, external linkage (vulgo: "global") variables is to call an initialization function at the start of main() that does all the initialization in the sequence you need:

“强制编译器接受代码”的方法是更改​​代码。执行文件范围,外部链接(vulgo:“global”)变量的任意初始化的规范方法是在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;
}

#1


11  

The official documentation, taken from line 1644, 6.7.8 Initialization, says:

官方文档取自1644行,6.7.8初始化,说:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

具有静态存储持续时间的对象的初始值设定项中的所有表达式应为常量表达式或字符串文字。

Why the rule exists is a more difficult question - perhaps as you suggest it is difficult for the compiler to do. In C++ such an expression is valid, but global initialiser may invoke constructors, etc, whereas for C, to keep things compact, globals are evaluated at the compile phase. int b = a; is evaluable at compile time, but what about int b = a + c;? int b = pow(a, 2);? Where would you stop? C decides that not allowing you to start is the best solution.

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

#2


4  

From your comment:

从你的评论:

...how can I force compiler to make this work?

...我如何强制编译器使其工作?

Well you can't make the compiler accept what you have but you can accomplish your goal by defining the value you want to assign to both variables.

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

#define INITIAL_VALUE_FOR_A 100

int a = INITIAL_VALUE_FOR_A;
int b = INITIAL_VALUE_FOR_A;

Now if you need to change the initial value, you only need to change it in one place;

现在,如果您需要更改初始值,您只需要在一个地方更改它;

#3


1  

C is portable to very simple, small machines. Evaluating expressions that aren't constant requires runtime code, in a function. In embedded programming you might not want any functions (or code) that you did not explicitly program.

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

Your compiler probably will evaluate the initializer as a language extension, if configured with different options. If that fails, you could try C++ (even just the C-like subset) or another language that does more things you like :v) .

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

#4


0  

Others have stated why initializers in general can't be allowed to be arbitrary expressions.

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

The way to "force the compiler to accept the code" is to change the code. The canonical way to perform arbitrary initialization of file scope, external linkage (vulgo: "global") variables is to call an initialization function at the start of main() that does all the initialization in the sequence you need:

“强制编译器接受代码”的方法是更改​​代码。执行文件范围,外部链接(vulgo:“global”)变量的任意初始化的规范方法是在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;
}