为什么以下代码会抛出错误?
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 ......)。那会发生什么?
答案 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)
作为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存储在何处