为什么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
关键字的意思是“只读”。 常量是数字文字,如42
或1.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式,并且始终为int
types(这意味着此方法对于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可以)”的值。