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

时间:2013-09-17 11:23:36

标签: c arrays const

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

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

当我尝试编译没有“const”关键字的上述代码时,我得到了同样的错误:

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

为什么会这样? 我在这里做的错误是什么?

还有另一个问题: 何时将常量替换为代码中的实际值,即如果我声明一个变量,则说:const int x = 5; 我知道在RAM中没有为变量x分配内存,但是ROM中的常量变量区域保持值5,并且x在代码中出现x的地方简单地替换为值5。但这什么时候发生的?编译时间?启动时间?预处理时间?

PS:我说的是嵌入式C(在微控制器上运行等),而不是在桌面上运行的C.因此嵌入式系统必然会有一个ROM(Flash,EEPROM ......)。那会发生什么?

5 个答案:

答案 0 :(得分:34)

这只是语言的限制。静态有界数组的大小需要是常量表达式,不幸的是在C中只有像文字常量或sizeof表达式之类的东西,但不是 a const - 类型变量。

(正如Simon指出的那样,因为C99还有运行时限制的数组或“可变长度数组”,其大小可以由任何变量的值给出。但这是一个不同的动物。)

您可能有兴趣听说C ++中的规则不同,其中static const int确实是一个常量表达式,而C ++ 11甚至添加了一个新关键字constexpr,以便均匀更广泛地使用常量表达式,其中包含更多的东西,其值“可以在编译时合理地确定”。

答案 1 :(得分:29)

在C中,const只读的用词不当。 const个变量可以更改其值,例如宣布

是完全可以的
const volatile int timer_tick_register; /* A CPU register. */

您可以阅读并获取每次读取的不同值,但不能写入。因此,语言规范将const限定对象视为适合数组大小的常量表达式。

答案 2 :(得分:20)

VLA的两个主要替代方案:RSYNC和宏

使用enum

enum

这是因为枚举成员是常量表达式:Can enum member be the size of an array in ANSI-C?

使用宏:

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

#define N 5 int is[N]; 的优点是enum具有范围,并且是编译步骤的一部分,因此它们也可能导致更好的错误消息。

宏的优点是你可以更好地控制常量的类型(例如enum vs #define N 1),而#define N 1u被固定为某种实现定义的类型:{ {3}}但在这种情况下它并不重要。

为什么要避免使用VLA

答案 3 :(得分:4)

编辑:只需在维基百科上阅读,C11已将可变长度数组降级为可选功能:( Doh!帖子的前半部分可能不是那么有用,但下半部分会回复你的一些其他问题:)

作为Kerrek SB的补充,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
}

sizeof运算符扩展如下:

  

sizeof运算符产生其操作数的大小(以字节为单位)   可以是表达式或类型的带括号的名称。大小是   根据操作数的类型确定。结果是整数。 如果   操作数的类型是可变长度数组类型,操作数   被评估;否则,不评估操作数和结果   是一个整数常量。

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

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

至于你的其他一些问题:

  

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

如果常量是一个const变量,那么它可能永远不会被“替换”,并且总是可以作为内存区域进行访问。这是因为地址运算符&仍然必须使用变量。但是,如果永远不使用变量地址,那么它可以被“替换”并且没有分配内存。从C标准:

  

实现可能会放置一个不易变的const对象   只读存储区域。而且,实施不需要   如果从未使用过地址,则为此类对象分配存储空间。

下一个问题......

  

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

这取决于您的系统。如果你有ROM并且编译器知道ROM的位置,那么它可能放在ROM中。如果没有ROM,编译器(真正的链接器)将有唯一的选择是RAM。

  

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

如上所述,这取决于常量的使用方式。如果从不使用const变量的地址并且编译器足够聪明,那么在complilation时间。否则,“替换”永远不会发生,它是一个在内存中具有位置的值;在这种情况下,变量在内存中的位置发生在链接时。在预处理期间永远不会发生。

答案 4 :(得分:1)

也许值得一提,在这里您可以使用

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

如果您需要元素数量

 size_t sz = sizeof(b)/sizeof(b[0]);

我相信这取决于工具链,以确定将常量,闪存或RAM存储在何处