为什么const局部阵列/结构在c中不静态



我正在为嵌入式系统编程,其中闪存存储空间和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...*/
}

jk在输入该功能时必须(重新)进行初始化,这意味着必须将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...*/
}

现在jk仅初始化一次,可以直接从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可能会有所作为,但对于内部功能的变量,如果要优化,请使用标志而不是conststatic

最新更新