为什么int x 错误,其中n是一个常量值?

我不明白为什么这样做是错误的:

const int n = 5; int x[n] = { 1,1,3,4,5 }; 

即使n已经是一个常量值。

虽然这样做似乎是正确的GNU编译器:

 const int n = 5; int x[n]; /*without initialization*/ 

我知道C99的VLA特性,我认为它与发生的事情有关,但我只需要澄清一下在后台发生的事情。

关键要记住的是, const和“constant”意味着两个完全不同的东西。

const关键字的意思是“只读”。 常量是数字文字,如421.5 (或枚举或字符常量)。 常量expression式是可以在编译时评估的特殊expression式,如2 + 2

所以给了一个声明:

 const int n = 5; 

expression式n表示对象的值,并不被视为常量expression式。 一个典型的编译器会优化对n的引用,用与文字5相同的代码replace它,但这不是必需的 – 而且expression式是否是常量的规则是由语言决定的,而不是由目前的编译器。

const (只读)和常量 (在编译时评估)之间的区别的一个例子是:

 const size_t now = time(NULL); 

const关键字意味着在初始化之后,你不允许修改now的值,但是直到运行时才能计算出time(NULL)的值。

所以这:

 const int n = 5; int x[n]; 

在C语言中比在没有const关键字的情况下更有效。

语言可能 (和恕我直言,可能应该)评价n作为一个常量的expression; 它只是没有这样定义。 (C ++确实有这样一个规则;请参阅C ++标准或关于血腥细节的体面参考。)

如果你想要一个名为5常量,最常用的方法是定义一个macros:

 #define N 5 int x[N]; 

另一种方法是定义一个枚举常量:

 enum { n = 5 }; int x[n]; 

枚举常量是常量expression式,并且始终为inttypes(这意味着此方法对于int以外的types不起作用)。 这可以说是滥用enum机制。

从1999年的标准开始,可以用一个非常数的大小定义一个数组; 这是一个VLA或可变长度的数组。 这样的数组只能在块范围中使用,并且可能没有初始化器(因为编译器无法检查初始化器是否具有正确数量的元素)。

但是给你的原始代码:

 const int n = 5; int x[n] = { 1,1,3,4,5 }; 

您可以让编译器从初始值设定项中推断出长度:

 int x[] = { 1,1,3,4,5 }; 

然后你可以从数组的大小计算长度:

 const int x_len = sizeof x / sizeof x[0]; 

为什么int x[n]是错误的,其中n是一个常量值?

n不是一个常数。 const只承诺n是一个'只读'variables,在程序执行过程中不应该被修改。
请注意,在c中 ,与c ++不同, const限定variables不是常量。 因此,声明的数组是一个可变长度的数组。
您不能使用初始化程序列表来初始化可变长度数组。

C11-§6.7.9/ 3:

要初始化的实体的types应该是未知大小的数组或不是可变长度数组types的完整对象types

你可以使用#define或者enum使n成为一个常量

 #define n 5 int x[n] = { 1,1,3,4,5 }; 

如果您正在彻底地初始化一个数组,那么让编译器推断数组大小会更简单,更安全,更易于维护:

 int x[] = { 1,1,3,4,5 }; const int n = sizeof(x) / sizeof(*x) ; 

然后要更改数组大小,只需更改初始化程序的数量,而不是更改大小初始化程序列表以匹配。 特别有用的时候有很多的初始化。

即使n是一个const ,除非你想创build一个VLA,否则你不能用它来定义一个数组的大小。 但是,您不能使用初始化程序列表来初始化VLA。

使用macros来创build一个固定大小的数组。

 #define ARRAY_SIZE 5 int x[ARRAY_SIZE] = { 1,1,3,4,5 }; 

你的代码在语义上与myfunc()不同:

 void myfunc(const int n) { int x[n] = { 1,1,3,4,5 }; printf("%d\n", x[n-1]); *( (int *) &n) = 17; // Somewhat less "constant" than hoped... return ; } int main(){ myfunc(4); myfunc(5); myfunc(6); // Haven't actually tested this. Boom? Maybe just printf(noise)? return 0; } 

n真的是所有这一切常数? 你认为编译器应该为x[]分配多less空间(因为编译器的工作是这样做的)?

正如其他人指出的那样,cv-qualifier const并不意味着“在编译期间和在所有时间之后的值”。 这意味着“本地代码不应该改变(尽pipe可以)”的值。