我无法理解为什么这样做是错误的:
const int n = 5;
int x[n] = { 1,1,3,4,5 };
即使n
已经是const值。
虽然这样做似乎适合GNU编译器:
const int n = 5;
int x[n]; /*without initialization*/
我知道C99的VLA功能,我认为这与正在发生的事情有关 我只需要澄清背景中发生的事情。
答案 0 :(得分:36)
要记住的关键是const
和"常数"意思是两件完全不同的东西。
const
关键字实际上意味着"只读"。 常量是一个数字文字,例如42
或1.5
(或枚举或字符常量)。 常量表达式是一种特殊的表达式,可以在编译时进行评估,例如2 + 2
。
所以给出一个声明:
const int n = 5;
表达式n
指的是对象的值,并且它不被视为常量表达式。典型的编译器将优化对n
的引用,用它用于文字5
的相同代码替换它,但不需要 - 以及表达式是否为常量由语言决定,而不是由当前编译器的聪明程度决定。
const
(只读)和常量(在编译时评估)之间的区别示例是:
const size_t now = time(NULL);
const
关键字表示您在初始化后不允许修改now
的值,但time(NULL)
的值在运行时之前无法计算。< / p>
所以这个:
const int n = 5;
int x[n];
在C中的有效性不会超过const
关键字。
语言可以(和IMHO可能应该)将n
评估为常量表达式;它并没有这样定义。 (C ++确实有这样的规则;请参阅C ++标准或关于血腥细节的合适参考。)
如果你想要一个值为5
的命名常量,最常见的方法是定义一个宏:
#define N 5
int x[N];
另一种方法是定义枚举常量:
enum { n = 5 };
int x[n];
枚举常量是常量表达式,并且始终为int
类型(这意味着此方法不适用于int
以外的类型)。它可以说是滥用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];
答案 1 :(得分:21)
为什么
int x[n]
在n
为const
值时出错?
n
不是常数。 const
仅承诺n
是一个'只读'变量,在程序执行期间不应修改该变量。
请注意,在c中,与c++不同,const
限定变量不是常量。因此,声明的数组是一个可变长度数组
您不能使用初始化列表来初始化可变长度数组。
C11-§6.7.9/ 3:
要初始化的实体的类型应为未知大小的数组或不是可变长度数组类型的完整对象类型。
您可以使用#define
或enum
使n
成为常量
#define n 5
int x[n] = { 1,1,3,4,5 };
答案 2 :(得分:7)
如果您对数组进行了详尽的初始化,那么让编译器推断数组大小会更容易,更安全,更易于维护:
int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ;
然后要更改数组大小,您只需更改初始化程序的数量,而不是更改和大小的初始化程序列表以匹配。当有许多初始化程序时特别有用。
答案 3 :(得分:3)
即使n
是const
,除非您希望创建VLA,否则不能使用它来定义数组的大小。但是,您无法使用初始化列表初始化VLA。
使用宏来创建固定大小的数组。
#define ARRAY_SIZE 5
int x[ARRAY_SIZE] = { 1,1,3,4,5 };
答案 4 :(得分:2)
您的代码在语义上与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[]
分配多少空间(因为这是编译器的工作)?
正如其他人所指出的那样,cv-qualifier const
不表示“在编译期间以及之后的所有时间都是常量的值”。它意味着“本地代码不应该改变的值(虽然它可以)”。