GCC 4.9和5.1 reject这个简单的C99声明在全球范围内。 Clang接受了它。
const int a = 1, b = a; // error: initializer element is not constant
如何丢失这样的基本功能?这似乎非常简单。
答案 0 :(得分:7)
C99 1 部分6.6 Constant expressions
是控制部分。它在小节6
和7
中列出:
6 /整数常量表达式应具有整数类型,并且只能具有 整数常量,枚举常量,字符常量,结果为整数常量的sizeof表达式以及立即浮点常量的操作数演员的操作数 。
整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof运算符的操作数的一部分。
整数和浮点常量的定义在标准的6.4.4
中指定,并且它仅限于实际的值(文字)而不是变量。
7 /初始值设定项中的常量表达式允许更多纬度。这样的常量表达式应该是或者评估为以下 (a)算术常量表达式之一,(b)空指针常量,(c)地址常量,或(d)地址对象类型的常量加上或减去整数常量表达式 。
由于a
<{1}}或6
中的7
none ,因此根据标准,它不被视为常量表达式。
因此,真正的问题不是为什么gcc
拒绝它,而是为什么clang
接受它,而这似乎隐藏在同一部分的10
小节中:
10 /实施 可能 接受其他形式的常量表达。
换句话说,标准规定了实现必须允许的常量表达式,但不限制实现只允许 。
1 C11与允许_Alignof
以及sizeof
之类的小问题大致相同。
答案 1 :(得分:2)
This is just the rules of C。一直都是这样。在文件范围内,初始值设定项必须是常量表达式。常量表达式的定义不包括使用const
限定符声明的变量。
要求初始化程序在编译时可计算的基本原理是,编译器可以将所有初始化的静态数据作为一个块放在可执行文件中,然后在加载时将bloc作为一个整体加载到内存中。瞧,全局变量都有正确的初始值,没有任何代码需要执行。
事实上,如果你可以将可执行代码作为全局变量的初始化器,那么它会引入很多关于应该运行代码的顺序的复杂性。(这在现代C ++中仍然是一个问题)。
在K&amp; R C中,没有const
。他们可以有一个规则,如果一个全局变量由常量表达式初始化,那么该变量也算作一个常量表达式。当在C89中添加const
时,他们可能还添加了const int a = 5;
导致常量表达式的规则。
然而他们没有。我不知道为什么肯定,但似乎它与保持语言简单有关。考虑一下:
extern const int a, b = a;
const int a = 5;
在另一个单位。无论你是否想要允许这一点,它对于编译器和一些更随意的决定来说要复杂得多。
如果你看一下当前用于常量表达式的C ++规则(这仍然不能让每个人满意!)你会看到每次你为一个“明显”的东西添加支持,那么还有另外两个“明显的”接下来的事情是永无止境的。
在C的早期,在20世纪70年代,保持编译器的简单性很重要,因此可能是编译器支持这意味着编译器使用了太多的系统资源或其他东西。 (希望那个时代的编码人员可以介入并对此发表更多评论!)
最后,C89标准化是一个非常有争议的过程,因为有很多不同的C编译器,每个编译器都有自己的语言演变方式。要求编译器供应商不支持这一点,改变他们的编译器以支持它可能会遇到反对,降低标准的使用。