我试着写ac程序如下?
const int x = 5;
int main()
{
int arr[x] = {1, 2, 3, 4, 5};
}
Run Code Online (Sandbox Code Playgroud)
当我尝试使用gcc进行编译时,这会发出警告,如下所示.
simple.c:9:错误:可能无法初始化变量大小的对象.
但是C++允许这样做.当我将x作为数组大小传递时,为什么x不被视为常量?
Kei*_*son 12
在C const中并不意味着"常量"(即,在编译时可评估).它只是意味着只读.
例如,在一个函数中,这个:
const int r = rand();
const time_t now = time(NULL);
Run Code Online (Sandbox Code Playgroud)
完全有效.
定义为的对象的名称const int不是常量表达式.这意味着(在C99之前的C和C++的所有版本中)它不能用于定义数组的长度.
虽然C99(以及可选的C11)支持可变长度数组(VLA),但它们无法初始化.原则上,编译器在定义VLA时不知道VLA的大小,因此无法检查初始化程序是否有效.在您的特定情况下,编译器很可能能够解决它,但语言规则旨在涵盖更一般的情况.
C++ 几乎相同,但C++有一个C缺乏的特殊规则:如果一个对象被定义为const,并且它的初始化是一个常量表达式,那么对象的名称本身就是一个常量表达式(至少对于整数类型).
C没有采用这个功能,这没有什么好的理由.在C中,如果你想要一个整数类型的名称常量,通常的方法是使用一个宏:
#define LEN 5
...
int arr[LEN] = {1, 2, 3, 4, 5};
Run Code Online (Sandbox Code Playgroud)
请注意,如果更改值LEN,则必须重新编写初始值设定项.
另一种方法是使用匿名enum:
enum { LEN = 5 };
...
int arr[LEN] = {1, 2, 3, 4, 5};
Run Code Online (Sandbox Code Playgroud)
枚举常量的名称实际上是常量表达式.在C中,由于历史原因,它始终是类型int; 在C++中,它是枚举类型.不幸的是,这一招只适用于类型的常量int,因此它限制为值从范围INT_MIN到INT_MAX.
当我将 x 作为数组大小传递时,为什么 x 不被视为常量?
因为在C中,常量表达式不能涉及任何变量的值,甚至是const变量的值。(这是 C 如此依赖宏常量的原因之一,而 C++ 会使用const变量来达到同样的目的。)
另一方面,在 C++ 中,如果声明为 ,x则肯定是常量表达式。xconst int x = 5;
如果您的问题是为什么C++ 在常量表达式方面比 C 自由得多,我认为它是为了支持元编程,并允许在编译时使用模板执行复杂的计算。
我想几乎每个人都误解了这个错误,错误说:
可变大小的对象可能无法初始化。
这是正确的,C99 和 C11(尽管它们在 C11 中是可选的)。它们不能在声明中初始化,我们可以从6.7.8 初始化部分看到这一点:
它被视为 VLA,因为与 C++ 不同,C 需要整数常量表达式:
如果大小是整数常量表达式并且元素类型具有已知的常量大小,则该数组类型不是变长数组类型;
整型常量表达式有以下限制:
应具有整数类型,并且只能具有整数常量、枚举常量、字符常量、结果为整数常量的 sizeof 表达式以及作为强制转换的直接操作数的浮点常量的操作数。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为 sizeof 运算符的操作数的一部分。
这x不满足。
要初始化的实体的类型应为未知大小的数组或不是变长数组类型的对象类型。
在 C++ 中,这不是一个可变长度数组,因为它x被视为常量表达式,我们可以从草案 C++ 标准部分“声明者”下的8.3.4 “数组”部分中看出,这是有效的,其中表示:8
在声明 TD 中,其中 D 的形式为
Run Code Online (Sandbox Code Playgroud)D1 [ constant-expressionopt] attribute-specifier-seqopt[...]如果存在常量表达式(5.19),则它应是 std::size_t 类型的转换常量表达式,并且其值应大于零。常量表达式指定数组(元素数量)的界限。如果常量表达式的值为 N,则数组有 N 个元素,编号为 0 到 N-1[...]
如果我们从声明中删除constx,它会因以下两个原因之一而失败:要么编译器支持 VLA 作为扩展,并且它会因为在 C 中失败的相同原因而失败,要么编译器不支持 VLA 作为扩展,并且因此该声明无效。