在if块中声明一个从未命中的函数级静态变量

时间:2010-11-29 14:41:40

标签: c

我对函数内声明的静态变量的理解是:

  1. 如果未指定初始值,则静态变量将驻留在.bss中,否则将位于.data
  2. 静态内存与全局变量一起分配 - 即在执行进入main之前
    • 这两个假设是否正确
  3. 执行第一次执行该功能时,静态将初始化为用户指定的值(如果未指定初始值,则为零)。
  4. ...并且它们在函数的后续调用中保留其值
  5. 但是如果我在if块中声明我的静态变量怎么办?我假设我的第三点应该更新为“当执行到达声明静态变量的行时,它们被初始化为......” - 我是否正确

    现在,如果它们被声明的if块从未被命中(并且编译器能够解决这个问题),那么我知道该变量永远不会被初始化;但是为该变量分配了任何内存吗?

    我写了两个函数来试图弄清楚发生了什么:

    #include <stdio.h>
    
    void foo()
    {
        static foo_var_out;
        if(0){
            static foo_var_in_0;
            printf("%d %d\n", foo_var_in_0);
        } else {
            static foo_var_in_1;
            printf("%d %d\n", foo_var_in_1);
        }   
    }
    
    static void bar(int flag)
    {
        static bar_var_out;
        if(flag){
            static bar_var_in_0;
            printf("%d %d\n", bar_var_in_0);
        } else {
            static bar_var_in_1;
            printf("%d %d\n", bar_var_in_1);
        }   
    }
    
    int main()
    {
        foo();
        bar(0);
    }
    

    我接受了对象转储:

    $ gcc -o main main.c
    $ objdump -t main | grep var
    45:080495c0 l     O .bss    00000004              foo_var_in_1.1779
    46:080495c4 l     O .bss    00000004              foo_var_out.1777
    47:080495c8 l     O .bss    00000004              bar_var_in_1.1787
    48:080495cc l     O .bss    00000004              bar_var_in_0.1786
    49:080495d0 l     O .bss    00000004              bar_var_out.1785
    

    从输出看起来根本没有创建foo_var_in_0(大概是因为它在显式if(0)内),而bar_var_in_0被创建(因为调用者可能)传递非零值 - 尽管唯一的调用者显式传递零。)

    我想我的问题是:假设根本没有为变量foo_var_in_0分配内存是否正确?我在问这个具体案例;我是否正确地阅读了objdump - 或者我应该做些什么来验证变量是否会在程序运行时占用一些内存?

    换句话说,如果从未命中声明函数级静态变量的行,那么实际上是否声明了变量?

    如果它根本不会被创建,这是根据C标准(不太可能),还是编译时优化以及在什么级别 - 如何将其打开/关闭(在gcc 4.1.1中)?

    我知道一个int并不是什么值得关注的事情,但我对它的工作原理更感兴趣;如果变量是一个大的数组,比如一个10字节结构的5000个元素呢?

3 个答案:

答案 0 :(得分:3)

  

假设根本没有为变量foo_var_in_0分配内存是否正确?

不,我不认为这是正确的。据我所知,这样的优化不是标准的一部分。

如果您知道编译器执行此操作并且您想要假设它,请继续。如果您编写任何需要这种情况的内容,您可能需要编写一个构建后测试以确保它发生。

你可能看到的是编译器的副作用,只是修剪了一些它知道永远不会运行的代码。意思是,它不是专门想要删除静态,但它确实删除了整个分支,因此其中的任何代码也被删除了。

答案 1 :(得分:2)

C标准没有规定放置变量和内容的位置。它只是规定符合要求的实现应具有等效行为(对于标准规定的参考行为),其中“等效”也由标准定义。

所以简单的答案就是它是一种优化,如何打开/关闭它取决于特定的编译器。

执行过程间分析的实现可能也可以摆脱bar_var_in_0

答案 2 :(得分:2)

只是为了添加其他人的正确答案。您对static变量初始化的假设不正确。

  • 带静态存储的变量是 总是初始化。要么是明确的 如果您提供初始化程序或 隐含地来自0
  • 此类变量的初始值设定项 必须始终是编译时间 不断表达。所以价值是 在编译时计算并编写 直接进入对象。 (好吧,如果它 全部为零,有些系统有技巧 /特殊部分避免 显式存储变量 目标文件。)
  • 所以,不,不会有初始化程序 语句在变量运行时运行 第一次访问(怎么会 系统知道,价值 另一个静态变量?)但是每当 你启动程序变量是 已初始化。