可以使用const变量在C中声明数组的大小吗?

时间:2021-05-17 21:48:17

Why does the following code throw an error?

为什么下面的代码会抛出错误?

const int a = 5;
int b[a]={1,2,3,4,5};

And also when I tried to compile the above code without "const" keyword, I got the same error:

另外,当我尝试不使用“const”关键字编译上述代码时,我得到了同样的错误:

int a = 5; 
int b[a]={1,2,3,4,5};

why is it so? What is the mistake that I am doing here?

为什么如此?我在这里犯的错误是什么?

And also another question: When are constants replaced with their actual values in a code, i.e if I declare a variable say: const int x= 5; I know that no memory is allocated in RAM for the variable x, but constant variable area in ROM holds the value 5 and that x is simply replaced by the value 5 everywhere x appears in the code. But when does this happen? Compilation time? Boot up time? Preprocessing time?

还有另一个问题:当常量在代码中被实际值替换时,i。e如果我声明一个变量,const int x= 5;我知道在RAM中没有为变量x分配内存,但是ROM中的常量变量区域保存了值5,并且只要代码中出现x, x就会被值5替换。但这是什么时候发生的呢?编译时间吗?启动时间?预处理时间吗?

PS: I am talking about Embedded C (running on a Microcontroller etc), not C running on my desktop. So the embedded system is bound to have a ROM (Flash, EEPROM...). What would happen then?

PS:我说的是嵌入式C(在单片机等上运行),而不是在我的桌面上运行的C。因此,嵌入式系统必然有一个ROM (Flash, EEPROM…)。会发生什么呢?

4 个解决方案

#1


29  

It's simply a limitation of the language. The sizes of statically-bounded arrays need to be constant expressions, and unfortunately in C that's only something like a literal constant or a sizeof expression or such like, but not a const-typed variable.

这只是语言的局限。静态有界数组的大小必须是常量表达式,不幸的是,在C语言中,这只是一个常量或者一个sizeof表达式之类的东西,而不是一个const类型的变量。

(As Simon pointed out, since C99 there are also runtime-bounded arrays, or "variable-length arrays", whose size can be given by the value of any variable. But that's a different animal.)

(正如Simon指出的,由于C99也有运行时有界的数组,或“可变长度数组”,它们的大小可以由任何变量的值给出。但那是另一种动物。

You may be interested to hear that the rules are different in C++, where a static const int is indeed a constant expression, and C++11 even adds a new keyword, constexpr, to allow even more general use of constant expressions which encompass more things whose value "could reasonably be determined at compile time".

你可能会有兴趣知道c++规则是不同的,在一个静态常量int的确是一个常数表达式,和c++ 11甚至添加了一个新的关键字,constexpr,允许更普遍使用的常量表达式包含更多的东西,其价值在编译时可以合理地确定。

#2


26  

In C, const is a misnomer for read-only. const variables can change their value, e.g. it is perfectly okay to declare

在C语言中,const是只读的误用。const变量可以改变它们的值,例如,声明是完全可以的

const volatile int timer_tick_register; /* A CPU register. */

which you can read and get a different value with each read, but not write to. The language specification thus treats const qualified objects not as constant expressions suitable for array sizes.

你可以阅读并得到不同的值,但不写。因此,语言规范将合格对象视为不适合数组大小的常量表达式。

#3


14  

2 major alternatives to VLA: enum and macros

VLA的两个主要替代方法:enum和macros

With enum:

枚举:

enum N { N = 5 };
int is[N];

This works because enum members are constant expressions: Can enum member be the size of an array in ANSI-C?

这样做是因为enum成员是常量表达式:enum成员可以是ANSI-C中的数组大小吗?

With macros:

宏:

#define N 5
int is[N];

The advantage of enums is that enums have scope, and are part of the compilation step, so they may lead to better error messages as well.

枚举的优点是枚举具有范围,并且是编译步骤的一部分,因此它们也可能导致更好的错误消息。

The advantage of macros is that you have more control over the type of the constants (e.g. #define N 1 vs #define N 1u), while enums are fixed to some implementation defined type: Is the sizeof(enum) == sizeof(int), always? But it doesn't matter much in this case.

宏的优点是您可以对常量的类型有更多的控制(例如#define N 1 vs #define N 1u),而enums是固定于某些实现定义的类型:sizeof(enum) = sizeof(int),总是吗?但在这种情况下这并不重要。

Why avoid VLA

为什么避免射电望远镜

#4


3  

EDIT: Just read on wikipedia that C11 has relegated variable length arrays to an optional feature :( Doh! The first half of the post may not be that useful but the second half answers some of your other questions :)

编辑:只要在*上读一下C11已经将可变长度数组降级为可选特性:(Doh!这篇文章的前半部分可能没那么有用,但后半部分回答了你的一些其他问题:

As an extra to Kerrek SB's post, C99 (ISO/IEC 9899:1999) does have the concept of a variable length array. The standard gives the following example:

C99 (ISO/IEC 9899:1999)确实有可变长度数组的概念。该标准给出如下例子:

#include <stddef.h>
size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}

The sizeof operator is extended as follows:

sizeof算子扩展如下:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

sizeof运算符产生其操作数的大小(以字节为单位),这可能是一个表达式或类型的圆括号名称。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是可变长度数组类型,则计算操作数;否则,操作数不计算,结果为整数常数。

Another nice example can be found on wikipedia.

另一个很好的例子可以在*上找到。

Note that statically declared cannot be variable length arrays.

注意,静态声明不能是可变长度数组。

As for some of your other questions:

至于你的其他问题:

Q: When are constants replaced with their actual values in a code?

问:什么时候用代码中的实际值替换常量?

If the constant is a const variable then it may never be "replaced" and could always be accessed as an area of memory. This is because the address-of operator & still has to work with the variable. However, if the variable address is never used then it can be "replaced" and have no memory allocated. From the C standard:

如果常量是const变量,那么它可能永远不会被“替换”,并且始终可以作为内存的一部分进行访问。这是因为操作符的地址&仍然需要处理变量。但是,如果不使用变量地址,那么它可以被“替换”,并且没有分配内存。从C标准:

The implementation may place a const object that is not volatile in a read-only region of storage. Moreover, the implementation need not allocate storage for such an object if its address is never used.

实现可以将不可变的const对象放置在存储的只读区域中。此外,如果从未使用该对象的地址,则实现不需要为该对象分配存储空间。

Next question...

下一个问题……

Q: I know that no memory is allocated in RAM for the variable x, but constant variable area in ROM holds the value 5

问:我知道在RAM中没有为变量x分配内存,但是ROM中的常量可变区域保持值5。

This depends on your system. If you have ROM and the compiler knows where ROM is located then it may well be placed in ROM. If there is no ROM the only choice the compiler (well linker really) will have is RAM.

这取决于你的系统。如果你有ROM,编译器知道ROM在哪里,那么它很可能被放在ROM中,如果没有ROM,编译器(链接器)唯一的选择就是RAM。

Q: x is simply replaced by the value 5 everywhere x appears in the code. But when does this happen? Compilation time? Boot up time? Preprocessing time?

Q: x在代码中出现的任何地方都被值5替换。但这是什么时候发生的呢?编译时间吗?启动时间?预处理时间吗?

As noted, this rather depends on how the constant is used. If the address of the const variable is never used and the compiler is clever enough, then at complilation time. Otherwise the "replacement" never occurs and it is a value with a location in memory; in this case the placement of the variable in memory happens at link time. It will never occur during preprocessing.

如前所述,这取决于如何使用常数。如果从未使用const变量的地址,并且编译器足够聪明,那么在遵从时。否则,“替换”不会发生,它是内存中有位置的值;在这种情况下,变量在内存中的位置发生在链接时间。在预处理过程中不会发生这种情况。

#1


29  

It's simply a limitation of the language. The sizes of statically-bounded arrays need to be constant expressions, and unfortunately in C that's only something like a literal constant or a sizeof expression or such like, but not a const-typed variable.

这只是语言的局限。静态有界数组的大小必须是常量表达式,不幸的是,在C语言中,这只是一个常量或者一个sizeof表达式之类的东西,而不是一个const类型的变量。

(As Simon pointed out, since C99 there are also runtime-bounded arrays, or "variable-length arrays", whose size can be given by the value of any variable. But that's a different animal.)

(正如Simon指出的,由于C99也有运行时有界的数组,或“可变长度数组”,它们的大小可以由任何变量的值给出。但那是另一种动物。

You may be interested to hear that the rules are different in C++, where a static const int is indeed a constant expression, and C++11 even adds a new keyword, constexpr, to allow even more general use of constant expressions which encompass more things whose value "could reasonably be determined at compile time".

你可能会有兴趣知道c++规则是不同的,在一个静态常量int的确是一个常数表达式,和c++ 11甚至添加了一个新的关键字,constexpr,允许更普遍使用的常量表达式包含更多的东西,其价值在编译时可以合理地确定。

#2


26  

In C, const is a misnomer for read-only. const variables can change their value, e.g. it is perfectly okay to declare

在C语言中,const是只读的误用。const变量可以改变它们的值,例如,声明是完全可以的

const volatile int timer_tick_register; /* A CPU register. */

which you can read and get a different value with each read, but not write to. The language specification thus treats const qualified objects not as constant expressions suitable for array sizes.

你可以阅读并得到不同的值,但不写。因此,语言规范将合格对象视为不适合数组大小的常量表达式。

#3


14  

2 major alternatives to VLA: enum and macros

VLA的两个主要替代方法:enum和macros

With enum:

枚举:

enum N { N = 5 };
int is[N];

This works because enum members are constant expressions: Can enum member be the size of an array in ANSI-C?

这样做是因为enum成员是常量表达式:enum成员可以是ANSI-C中的数组大小吗?

With macros:

宏:

#define N 5
int is[N];

The advantage of enums is that enums have scope, and are part of the compilation step, so they may lead to better error messages as well.

枚举的优点是枚举具有范围,并且是编译步骤的一部分,因此它们也可能导致更好的错误消息。

The advantage of macros is that you have more control over the type of the constants (e.g. #define N 1 vs #define N 1u), while enums are fixed to some implementation defined type: Is the sizeof(enum) == sizeof(int), always? But it doesn't matter much in this case.

宏的优点是您可以对常量的类型有更多的控制(例如#define N 1 vs #define N 1u),而enums是固定于某些实现定义的类型:sizeof(enum) = sizeof(int),总是吗?但在这种情况下这并不重要。

Why avoid VLA

为什么避免射电望远镜

#4


3  

EDIT: Just read on wikipedia that C11 has relegated variable length arrays to an optional feature :( Doh! The first half of the post may not be that useful but the second half answers some of your other questions :)

编辑:只要在*上读一下C11已经将可变长度数组降级为可选特性:(Doh!这篇文章的前半部分可能没那么有用,但后半部分回答了你的一些其他问题:

As an extra to Kerrek SB's post, C99 (ISO/IEC 9899:1999) does have the concept of a variable length array. The standard gives the following example:

C99 (ISO/IEC 9899:1999)确实有可变长度数组的概念。该标准给出如下例子:

#include <stddef.h>
size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}

The sizeof operator is extended as follows:

sizeof算子扩展如下:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

sizeof运算符产生其操作数的大小(以字节为单位),这可能是一个表达式或类型的圆括号名称。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是可变长度数组类型,则计算操作数;否则,操作数不计算,结果为整数常数。

Another nice example can be found on wikipedia.

另一个很好的例子可以在*上找到。

Note that statically declared cannot be variable length arrays.

注意,静态声明不能是可变长度数组。

As for some of your other questions:

至于你的其他问题:

Q: When are constants replaced with their actual values in a code?

问:什么时候用代码中的实际值替换常量?

If the constant is a const variable then it may never be "replaced" and could always be accessed as an area of memory. This is because the address-of operator & still has to work with the variable. However, if the variable address is never used then it can be "replaced" and have no memory allocated. From the C standard:

如果常量是const变量,那么它可能永远不会被“替换”,并且始终可以作为内存的一部分进行访问。这是因为操作符的地址&仍然需要处理变量。但是,如果不使用变量地址,那么它可以被“替换”,并且没有分配内存。从C标准:

The implementation may place a const object that is not volatile in a read-only region of storage. Moreover, the implementation need not allocate storage for such an object if its address is never used.

实现可以将不可变的const对象放置在存储的只读区域中。此外,如果从未使用该对象的地址,则实现不需要为该对象分配存储空间。

Next question...

下一个问题……

Q: I know that no memory is allocated in RAM for the variable x, but constant variable area in ROM holds the value 5

问:我知道在RAM中没有为变量x分配内存,但是ROM中的常量可变区域保持值5。

This depends on your system. If you have ROM and the compiler knows where ROM is located then it may well be placed in ROM. If there is no ROM the only choice the compiler (well linker really) will have is RAM.

这取决于你的系统。如果你有ROM,编译器知道ROM在哪里,那么它很可能被放在ROM中,如果没有ROM,编译器(链接器)唯一的选择就是RAM。

Q: x is simply replaced by the value 5 everywhere x appears in the code. But when does this happen? Compilation time? Boot up time? Preprocessing time?

Q: x在代码中出现的任何地方都被值5替换。但这是什么时候发生的呢?编译时间吗?启动时间?预处理时间吗?

As noted, this rather depends on how the constant is used. If the address of the const variable is never used and the compiler is clever enough, then at complilation time. Otherwise the "replacement" never occurs and it is a value with a location in memory; in this case the placement of the variable in memory happens at link time. It will never occur during preprocessing.

如前所述,这取决于如何使用常数。如果从未使用const变量的地址,并且编译器足够聪明,那么在遵从时。否则,“替换”不会发生,它是内存中有位置的值;在这种情况下,变量在内存中的位置发生在链接时间。在预处理过程中不会发生这种情况。