我正在为嵌入式系统编程,其中闪存存储空间和RAM使用都是一个问题。
根据C11标准第6.2.4节:
一个没有链接的对象,其标识符没有存储级规范符
执行中都能执行声明或复合文字时执行它。static
具有自动存储持续时间 ...对象的初始值不确定。如果 为对象指定初始化,每次在执行块
如果我正确理解,这意味着这样的功能:
static void func(void){
const struct MyStruct j={5,6,7,8};
const char k[]="long string of some sort";
/*...some code...*/
}
j
和 k
在输入该功能时必须(重新)进行初始化,这意味着必须将J和K的存储位置放在RAM中,并从flash的数据部分中初始化,并使用Memcpy之类的东西进行初始化。这意味着它在RAM和Flash中都使用资源。与:
static void func(void){
static const struct MyStruct j={5,6,7,8};
static const char k[]="long string of some sort";
/*...some code...*/
}
现在j
和k
仅初始化一次,可以直接从Flash引用而不复制到RAM。
不宣布您(大于寄存器大小)const
s为static
?
基本上,我想知道我是否应该始终将我的const
S称为static
,或者是否有理由不这样做。
我对此进行了一些实验,这是代码:
extern void other_call (int);
extern void other_call2 (const char *);
void test ()
{
const int var = 32;
const char * const var2 = "this is a string";
int var3;
other_call (var);
var3 = var * 10;
other_call2 (var2);
other_call (var3);
}
然后我用:
构建它arm-none-eabi-gcc -std=gnu99 -O0 -fno-common -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections "-Wa,-adhln=test.s" -mcpu=cortex-m0 -mthumb -specs=redlib.specs -MMD -MP "../src/test.c"
并在const
初始化上获得了此组件:
42 0004 00AF add r7, sp, #0
6:../src/test.c **** const int var = 32;
44 .loc 1 6 0
45 0006 2023 movs r3, #32
46 0008 FB60 str r3, [r7, #12]
7:../src/test.c **** const char * var2 = "this is a string";
47 .loc 1 7 0
48 000a 0C4B ldr r3, .L2
49 000c BB60 str r3, [r7, #8]
编译器加载了const值32至R3,然后将其存储在RAM中(R7加载了SP)。对于字符串var2
,编译器将与Cosntant号码相同,除了它将使用.l2,这是字符串地址的位置。
请注意,它确实在没有必要的情况下将变量写入了堆栈,因为它们是const的,并且不会更改。
现在使用`-o3:
启用优化 6:../src/test.c **** const int var = 32;
7:../src/test.c **** const char * var2 = "this is a string";
8:../src/test.c **** int var3;
9:../src/test.c ****
10:../src/test.c **** other_call (var);
37 .loc 1 10 0
38 0002 2020 movs r0, #32
39 0004 FFF7FEFF bl other_call
40 .LVL1:
11:../src/test.c **** var3 = var * 10;
12:../src/test.c **** other_call2 (var2);
41 .loc 1 12 0
42 0008 0348 ldr r0, .L2
43 000a FFF7FEFF bl other_call2
请注意,不涉及堆栈操作。它加载了寄存器的权利,并跳到使用它们的功能。甚至VAR3也被优化了。
让我们看看没有const
预选赛会发生什么?好吧,我不必发布任何组件,因为它没有什么不同。在提议的代码中,const
限定符在生成的组件中没有任何更改。即使在Optmization上,-O0
编译器仍将为const变量构成堆栈。如果您真的想强制执行编译器以避免堆栈,请进行优化。我还用#define
而不是const
测试了它,但它仍然使用-O0
上的堆栈。
现在,转动变量static
,编译器做了应该做的事情,它将变量存储在RAM中,并在使用-O3
之前将其加载到寄存器中。通过优化,启用了编译器,简单地忽略了该示例的static
。考虑变量仅读取,并且从未写入此优化是正确的。
我知道这是一个单个编译器的一种情况,但是在大多数情况下,它是代表性的,在某些情况下,const
可能会有所作为,但对于内部功能的变量,如果要优化,请使用标志而不是const
和static
。