为什么C中的静态初始化表达式不能使用常量数组的元素?

del*_*106 4 c arrays initialization constant-expression

以下(公认的做作)C程序无法编译:

int main() {
const int array[] = {1,2,3};
static int x = array[1];
}
Run Code Online (Sandbox Code Playgroud)

使用gcc(或Microsoft的CL.EXE)编译上述C源文件时,出现以下错误:

error: initializer element is not constant
static int x = array[1];
               ^
Run Code Online (Sandbox Code Playgroud)

这种简单直观的语法肯定是有用的,所以这似乎应该是合法的,但显然它不是.当然,我不是唯一一个对这种明显愚蠢的限制感到沮丧的人.我不明白为什么这是不允许的 - 通过使这个有用的语法非法,C语言试图避免什么问题?

看起来它可能与编译器为初始化生成汇编代码的方式有关,因为如果删除"static"关键字(使得变量"x"在堆栈上),那么它编译得很好.

然而,另一个奇怪的事情是它在C++中编译得很好(即使使用static关键字),但在C中却没有.因此,C++编译器似乎能够生成必要的汇编代码来执行这样的初始化.

编辑:相信戴维斯 - 为了安抚SO权力 - 我会寻求以下类型的事实信息来回答这个问题:

  1. 是否有支持这些语义的遗留代码会破坏?

  2. 这些语义是否已经正式提交给标准委员会?

  3. 有没有人有理由拒绝这些语义的允许?

dbu*_*ush 5

具有静态存储持续时间的对象(读取:在文件范围或使用static关键字声明的变量)必须由编译时常量初始化.

关于初始化状态的C标准第6.7.9节:

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

关于常量表达式的6.6节说明:

7初始值设定项中的常量表达式允许更多的纬度.这样的常量表达式应为或评估为以下之一:

  • 算术常量表达式,
  • 空指针常量,
  • 地址常数,或
  • 完整对象类型的地址常量加上或减去整数常量表达式.

8算术常量表达式应具有算术类型,并且只能具有整数常量,浮点常量,枚举常量,字符常量,结果为整数常量的sizeof表达式和_Alignof表达式的操作数.算术常量表达式中的转换运算符只能将算术类型转换为算术类型,除非作为sizeof或_Alignof运算符的操作数的一部分.

9地址常量是空指针,指向左值的指针,指定静态存储持续时间的对象,或指向函数指示符的指针; 它应该使用一元&运算符或一个转换为指针类型的整数常量显式创建,或者通过使用数组或函数类型的表达式隐式创建.array-subscript []和member-access.和 - >运算符,地址&和间接*一元运算符和指针强制转换可用于创建地址常量,但不能使用这些运算符访问对象的值.

通过上面的定义,const变量不符合常量表达式,因此不能用于初始化static对象.另一方面,C++ 确实const变量视为真正的常量,因此允许它们初始化静态对象.