为什么 int x[n] 错误,其中 n 是一个 const 值?
Why is int x[n] wrong where n is a const value?
我不明白为什么这样做是错误的:
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 功能,我认为它与正在发生的事情有关,但是
我只需要澄清一下后台发生的事情。
Why int x[n]
is wrong where n
is a const
value?
n
不是常数。 const
只承诺 n
是一个 'read-only' 变量,在程序执行期间不应修改。
请注意,在 c, unlike c++ 中,const
限定变量不是常量。因此声明的数组是变长数组
您不能使用初始化列表来初始化可变长度数组。
C11-§6.7.9/3:
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
您可以使用 #define
或 enum
使 n
成为常量
#define n 5
int x[n] = { 1,1,3,4,5 };
即使 n
是一个 const
,你也不能用它来定义数组的大小,除非你想创建一个 VLA。但是,您不能使用初始化列表来初始化 VLA。
使用宏创建固定大小的数组。
#define ARRAY_SIZE 5
int x[ARRAY_SIZE] = { 1,1,3,4,5 };
如果您要彻底初始化一个数组,那么让编译器推断数组大小会更容易、更安全且更易于维护:
int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ;
然后要更改数组大小,您只需更改初始化器的数量,而不是更改大小 和 初始化器列表以匹配。当有很多初始化程序时特别有用。
要记住的关键是 const
和 "constant" 是两个完全不同的意思。
const
关键字的实际意思是 "read-only"。 常量 是数字文字,例如 42
或 1.5
(或枚举或字符常量)。 常量表达式 是一种特殊的表达式,可以在编译时求值,例如 2 + 2
.
所以给出一个声明:
const int n = 5;
表达式n
引用对象的值,它不被视为常量表达式。典型的编译器会优化对 n
的引用,将其替换为用于文字 5
的相同代码,但这不是必需的——表达式是否为 [=68= 的规则]constant 是由语言决定的,而不是由当前编译器的聪明程度决定的。
const
(只读)和常量(在编译时评估)之间的区别示例是:
const size_t now = time(NULL);
关键字const
表示now
的值在初始化后不允许修改,但是time(NULL)
的值显然不能计算到运行 ] 时间。
所以这个:
const int n = 5;
int x[n];
在 C 语言中不再比没有 const
关键字更有效。
语言可以(恕我直言,可能应该)将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];
您的代码在语义上是否与此处的 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[]
分配多少 space(因为这是编译器的工作)?
正如其他人指出的那样,cv 限定符 const
不是 的意思是 "a value that is constant during compilation and for all times after"。意思是"a value that the local code is not supposed to change (although it can)".
我不明白为什么这样做是错误的:
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 功能,我认为它与正在发生的事情有关,但是 我只需要澄清一下后台发生的事情。
Why
int x[n]
is wrong wheren
is aconst
value?
n
不是常数。 const
只承诺 n
是一个 'read-only' 变量,在程序执行期间不应修改。
请注意,在 c, unlike c++ 中,const
限定变量不是常量。因此声明的数组是变长数组
您不能使用初始化列表来初始化可变长度数组。
C11-§6.7.9/3:
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
您可以使用 #define
或 enum
使 n
成为常量
#define n 5
int x[n] = { 1,1,3,4,5 };
即使 n
是一个 const
,你也不能用它来定义数组的大小,除非你想创建一个 VLA。但是,您不能使用初始化列表来初始化 VLA。
使用宏创建固定大小的数组。
#define ARRAY_SIZE 5
int x[ARRAY_SIZE] = { 1,1,3,4,5 };
如果您要彻底初始化一个数组,那么让编译器推断数组大小会更容易、更安全且更易于维护:
int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ;
然后要更改数组大小,您只需更改初始化器的数量,而不是更改大小 和 初始化器列表以匹配。当有很多初始化程序时特别有用。
要记住的关键是 const
和 "constant" 是两个完全不同的意思。
const
关键字的实际意思是 "read-only"。 常量 是数字文字,例如 42
或 1.5
(或枚举或字符常量)。 常量表达式 是一种特殊的表达式,可以在编译时求值,例如 2 + 2
.
所以给出一个声明:
const int n = 5;
表达式n
引用对象的值,它不被视为常量表达式。典型的编译器会优化对 n
的引用,将其替换为用于文字 5
的相同代码,但这不是必需的——表达式是否为 [=68= 的规则]constant 是由语言决定的,而不是由当前编译器的聪明程度决定的。
const
(只读)和常量(在编译时评估)之间的区别示例是:
const size_t now = time(NULL);
关键字const
表示now
的值在初始化后不允许修改,但是time(NULL)
的值显然不能计算到运行 ] 时间。
所以这个:
const int n = 5;
int x[n];
在 C 语言中不再比没有 const
关键字更有效。
语言可以(恕我直言,可能应该)将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];
您的代码在语义上是否与此处的 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[]
分配多少 space(因为这是编译器的工作)?
正如其他人指出的那样,cv 限定符 const
不是 的意思是 "a value that is constant during compilation and for all times after"。意思是"a value that the local code is not supposed to change (although it can)".