是否可以指示C不对全局数组进行零初始化?

时间:2013-02-04 11:40:54

标签: c gcc embedded c99

我正在编写一个嵌入式应用程序,几乎所有的RAM都被全局字节数组使用。当我的固件启动时,它会通过用零覆盖RAM中的整个BSS部分来启动,这在我的情况下是完全没有必要的。

是否有某种方法可以指示编译器不需要对某些数组进行零初始化?我知道这也可以通过将它们声明为指针并使用malloc()来解决,但有几个原因我想避免这种情况。

7 个答案:

答案 0 :(得分:10)

问题是标准C 强制静态对象的零初始化。如果编译器跳过它,它将不符合C标准。

在嵌入式系统编译器上,通常存在非标准选项“紧凑启动”或类似。启用后,程序中的任何位置都不会发生静态/全局对象的初始化。如何执行此操作取决于您的编译器,或者在本例中,取决于您的gcc端口。

如果您提到您正在使用的系统,则有人可能能够为该特定编译器端口提供解决方案。

这意味着您将显式初始化的任何静态/全局(静态存储持续时间)变量将不再被初始化。您必须在运行时初始化它,也就是说,您必须编写static int x=1;而不是static int x; x=1;。以这种方式编写嵌入式C程序是很常见的,以使它们与禁用静态初始化的编译器兼容。

答案 1 :(得分:9)

事实证明,我的工具链中包含的链接器脚本有一个特殊的“noinit”部分。

__attribute__ ((section (".noinit")))
  

/ **强制编译器不自动将给定的全局置零   启动时变量,以便保留当前的RAM内容。    在大多数情况下,由于该值,该值将是随机的   一旦移除电源,易失性存储器的行为,但可能在某些特定情况下使用   情况,就像在系统看门狗复位后传回值一样。

因此,所有标有该属性的全局变量都不会在启动时进行零初始化。

答案 2 :(得分:2)

C标准要求将全局数据初始化为零。

有些嵌入式系统制造商可能会提供绕过此选项的方法,但是如果没有“初始化为零”,肯定有许多典型的应用程序会失败。

某些编译器还允许您使用其他部分,这些部分可能具有“bss”部分之外的其他特征。

另一种选择当然是“自己分配”。由于它是一个嵌入式系统,我认为您可以控制应用程序和数据如何加载到RAM中,特别是用于此的地址。

因此,你可以使用一个指针,只需使用你自己的机制将指针指向一个内存区域,该内存区域是为你需要的大数组而保留的。这避免了malloc的相当复杂的使用 - 并且它为您提供了或多或少的永久地址,因此您不必担心尝试查找以后数据的位置。这当然会对性能产生很小的影响,因为它增加了另一个间接层,但在大多数情况下,一旦数组用作函数的参数,它就会消失,因为它会在该点衰减到指针

答案 3 :(得分:2)

有一些解决方法,如:

  • 从二进制文件中删除BSS部分或将其大小设置为0或1.如果加载程序必须为所有部分显式分配内存,则无效。如果加载器只是将数据复制到RAM中,这将起作用。
  • 在C代码中将数组声明为extern,并在单独的汇编文件或链接描述文件中的汇编代码中定义符号(及其地址)。同样,如果必须明确分配内存,这将不起作用。
  • main()之前,在加载程序或程序中执行的启动代码中修补或删除相关的BSS归零代码。

答案 4 :(得分:2)

所有嵌入式编译器都应该允许一个noinit段。使用IAR AVR编译器,您不希望初始化的变量只是声明如下:

__ no_init uint16_t foo;

最有用的原因是允许变量在看门狗或欠压复位时保持其值,这当然不会发生在基于计算机的C程序中,因此它从标准C中省略。 / p>

只需在编译器手册中搜索" noinit"或类似的东西。

答案 5 :(得分:1)

您确定二进制格式实际上包含二进制文件中的BSS部分吗?在二进制格式中,我使用BSS只是一个整数,它告诉内核/加载器要分配多少内存并将其清零。

在C中肯定没有通用的方法来获取未初始化的全局变量。这将是您的编译器/链接器/运行时系统的一个功能,并且非常具体。

答案 6 :(得分:0)

使用gcc,-fno-zero-initialized-in-bss