一个constvariables可以用来声明C中数组的大小吗?
为什么下面的代码会抛出一个错误?
const int a = 5; int b[a]={1,2,3,4,5};
而且当我试图编译上面的代码没有“const”关键字时,我得到了同样的错误:
int a = 5; int b[a]={1,2,3,4,5};
为什么这样呢? 我在这里做的错误是什么?
还有另一个问题:什么时候将常量replace为代码中的实际值,即如果我声明一个variables说:const int x = 5; 我知道RAM中没有为variablesx分配内存,但是在ROM中的常量variables区域保存了值5,并且在代码中出现x的地方x简单地由值5代替。 但是这是什么时候发生的? 编译时间? 开机时间? 预处理时间?
PS:我正在谈论embedded式C(运行在微控制器等),而不是C在我的桌面上运行。 所以embedded式系统必然有一个ROM(Flash,EEPROM …)。 那么会发生什么?
这只是语言的限制。 静态有界数组的大小需要是常量expression式 ,不幸的是,在C中,它只是像文字常量或sizeof
expression式之类的东西,而不是 const
型的variables。
(正如Simon指出的那样,自C99以来,也有运行时限制的数组或“变长数组”,其大小可以由任何variables的值给出,但是这是一个不同的动物)。
您可能有兴趣听说C ++中的规则是不同的,其中static const int
确实是一个常量expression式,并且C ++ 11甚至添加了一个新的关键字constexpr
,以允许更常规地使用包含更多价值“可以在编译时合理确定”的东西。
在C中, const
对于只读是一个用词不当的。 const
variables可以改变它们的值,例如声明是完全可以的
const volatile int timer_tick_register; /* A CPU register. */
你可以阅读,并获得一个不同的值,每个阅读,但不写。 因此,语言规范不会将const
限定对象视为适合数组大小的常量expression式。
VLA的两个主要替代方法: enum
和macros
用enum
:
enum N { N = 5 }; int is[N];
这是因为枚举成员是常量expression式: 枚举成员可以在ANSI-C中的数组的大小?
用macros:
#define N 5 int is[N];
enum
的优点是enum
有范围,并且是编译步骤的一部分,所以它们也可以导致更好的错误信息。
macros的优点是你有更多的控制常量的types(例如#define N 1
vs #define N 1u
),而enum
s固定为一些实现定义的types: sizeof(enum)== sizeof(诠释),总是? 但在这种情况下并不重要。
为什么要避免VLA
- 不在C89中,只在C11中可选
- 可能会产生开销: 使用可变长度数组是否有任何开销? (可能很less)
编辑:刚刚阅读维基百科C11已经把可变长度arrays降级到一个可选的function:( 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运算符产生其操作数的大小(以字节为单位),该操作数可以是一个expression式或一个types的括号内的名称。 大小取决于操作数的types。 结果是一个整数。 如果操作数的types是可变长度数组types,则评估操作数 ; 否则,操作数不计算,结果是一个整数常量。
另一个很好的例子可以在维基百科上find。
请注意,静态声明不能是可变长度数组。
至于其他一些问题:
问:什么时候用代码中的实际值代替常量?
如果常量是一个常量variables,那么它可能永远不会被“replace”,并且总是可以作为内存区域被访问。 这是因为操作员的地址仍然必须与variables一起工作。 但是,如果variables地址从不使用,则可以“replace”并且没有分配内存。 从C标准:
该实现可能会将一个非易失性的const对象放置在只读存储区域。 此外,如果从不使用地址,则实现不需要为这样的对象分配存储空间。
下一个问题…
问:我知道RAM中没有为variablesx分配内存,但是ROM中的常量variables区域保存了值5
这取决于你的系统。 如果你有ROM并且编译器知道ROM所在的位置,那么它可能被放在ROM中。 如果没有ROM,那么编译器(连接器真的)的唯一select就是RAM。
问:简单地用代码中的x代替x。 但是这是什么时候发生的? 编译时间? 开机时间? 预处理时间?
如上所述,这取决于如何使用常数。 如果constvariables的地址从不使用,并且编译器足够聪明,那么在编译时。 否则,“replace”从不会发生,并且它是一个位于内存中的值; 在这种情况下,variables在内存中的位置发生在链接时间。 在预处理过程中不会发生。