是否有有效的理由可以在C程序的Main()函数内声明变量静态



我知道c中静态关键字的各种含义,但是我的问题更具体:是否有任何有效的理由在嵌入式的main()函数中声明某些变量C语言程序是静态的?

由于我们正在谈论main()括号内声明的变量,因此 scope 已经是main()的本地化。关于持久性,主函数位于呼叫堆栈的顶部,只要程序正在运行,就无法退出。因此,从表面上看,似乎没有正当理由使用main内部静态()。

但是,我注意到使用静态声明的效果是防止变量和数组放在堆栈上。如果堆栈尺寸有限,这可能很重要。

另一个可能的情况,但罕见的情况是main()递归调用自己的情况,您可能需要一些变量才能在递归的不同级别上持续存在。

是否还有其他可能使用Main()函数体内变量静态声明的有效理由?

..使用Main()函数体内变量静态声明的有效理由?

  1. 初始化

    int main(void) {
      static int a;  // initialized to 0
      int b;  // uninitialized
    
  2. 在C中,main()呼叫。参考,因此适用有关static变量的通常问题。

    int main(void) {
      static int c;  // Only one instance
      int d;         // One instance per call
      ...
      main();
    
  3. 内存位置。各种编译器将组织main()的变量。它不是由C指定的,因此依赖编译器的问题。

一个变量除了类型以外还有三个属性:

  • 范围(可见性)
  • 一生
  • 位置

选择这些属性的选择是根据代码语义进行的。虽然main()中的static变量可能会出现具有与非静态相同的范围和寿命,因此仅在位置上有所不同,但它没有相同的 Semantics 。如果 - 可能正在开发 - 您决定将main()中的代码移动或重组为子列表,则使用static将导致此类代码的行为不同,并且可能错误地。

我的建议因此是,您使用static中使用CC_8的使用与任何其他功能相同,并且不会将其视为A 特殊情况与非静态相同的特殊情况。这种方法不会导致可重复使用或可维护的代码。

在任何情况下,如果您有一个堆栈变量,则必须将内存划分为堆栈,堆和静态空间因此,这并不是真正的论点,除了不足的内存是一个构建时间问题而不是运行时的事实,但是如果这是一个严重的问题,您可能会考虑制作 all> all 大多数变量当然是静态的(一定会排除重新进入,因此递归和多线程)。如果堆栈空间确实是一个问题,那么在任何情况下,递归都是一个坏主意 - 在大多数情况下,这是一个坏主意,当然也是main()的递归。

我看到了在main内部声明static变量的实际原因(大多数编译器在大多数台式机或笔记本电脑操作系统上):main内部的本地变量正在消耗呼叫堆栈上的空间。static变量消耗space 外部 call stack(通常在.bss.data段中,至少在Elf可执行文件中)

如果该变量占用很大的空间(想想一百万个整数),那将产生很大的不同。

堆栈空间通常限制(台式机,笔记本电脑,平板电脑)系统(台式机)系统。

在某些嵌入式处理器上,堆栈仅限于一千字节。

我认为您已经说过。它使它们成为静态的静态(对于main()不是很有趣,其次,它使它们称为我所说的本地全球群体,从本质上讲,它们将它们与全球群体(而不是堆栈)一起放在.data中,而是限制了它们的访问范围本地人。因此,对于main(),我想原因是要保存一些堆栈。如果您在堆栈溢出周围阅读,尽管似乎有些编译器在Main()上都放置了一个很大的堆栈框架,大多数情况下,这确实没有道理,那么您真的可以节省任何空间吗?同样,如果它们从Main堆叠在Main上,除非您递归地调用Main,否则它们不会在.data与堆栈中更少或多或少地占用空间。如果将它们优化到寄存器中,那么您仍然燃烧.data,您将不会燃烧堆栈空间,因此它可能会花费您一些空间。

试图间接访问用自动存储持续时间定义的对象的结果,即与对象相关联的不同线程中的本地变量已定义(请参阅:6.2,请参见:6.2.4对象的存储持续时间,p5)。

如果您希望代码可移植,则应仅与用静态,线程或分配的存储持续时间定义的线程对象共享。

在此示例中,主在MAIM中定义的自动object应该用静态定义:

int main( void )
{
    CreateThreads();
    type object = { 0 };   //missing static storage-class specifier
    ShareWithThreads( &object );
}

如前所述,主要原因是节省堆栈空间,并使您更好地了解程序的实际堆栈大小。

声明此类变量static的另一个原因是程序安全。这里需要考虑各种嵌入式系统设计规则:

堆栈应始终是内存映射的,以使其朝着无效的内存生长,而不是朝.bss.data生长。这意味着,在堆栈溢出的情况下,该程序有机会提出异常,而不是在您的静态变量上进行丰田。

出于类似的原因,您应该避免在堆栈上声明大量数据,因为这使得代码更容易堆叠溢出。这特别适用于小型内存约束的微控制器系统。


另一个可能的情况,而是不常见的情况是main()递归自称

这是胡说八道,没有理智的人会编写这样的代码。在嵌入式系统中使用递归是非常可疑的实践,通常被编码标准禁止。事实是,在很少有情况下,递归在任何程序中都有意义。

曾经原因是,在链接时间确定可执行文件中静态变量的偏移,并且可以依靠在同一位置。

因此,主要级别静态变量的有用目的是将程序版本数据作为可读字符串或二进制可读数据包括在内,后来可用于分析/组织可执行文件,而无需具有原始源代码或任何程序 - 特定的公用事业,除了十六进制垃圾箱计划。我们在部署程序无法依靠任何开发工具的那一天使用了此黑客。

例如,

int main(void)
{
    // tag to search for revision number
    static char versionID[3] = {'V','E','R'};
    // statically embedded program version is 2.1
    static unsigned char major_revision = 2;
    static unsigned char minor_revision = 1;
    printf("nHello World");
    return 0;
}

现在可以在不运行的情况下确定程序的版本:

$ od -c -c -x helly -world |grep" v e r"

0010040 001 002 v e r g c c c :( u b u n t

实际上,有一个很大的原因!

如果您将变量声明为 static main() (或任何功能...)中,则您正在声明此 local 变量也是 static

这意味着,如果此功能自称为...(main()可能不会做,尽管它肯定可以...)...每个递归实例都会看到相同的值,因为此变量不是分配在堆栈上。(因为,嗯,"它是 static!")

"堆栈大小"是不是使用static.的有效理由(实际上,它与之无关。)如果您担心存储"堆栈上的空间"以存储正确的做法是使用 Pointer 变量"将其存储在堆中"。(像任何变量一样,它可能是静态的。)

最新更新