【问题标题】:Query on the scope of local variables in C查询C中局部变量的范围
【发布时间】:2011-03-03 13:01:09
【问题描述】:

全部,

考虑以下代码:

void func(void)
{
    int a;
    printf ("%d", a);
}

int main(int argc, char **argv)
{
    int a = 3;
    func();
    printf("%d", a);
}

根据我的理解,输出应该是:

<junk value><3>

谁能确认我的理解?我的基本查询是,编译器是否引用了已声明但未定义的变量的外部范围?

问候, 小黑子

【问题讨论】:

    标签: c scope


    【解决方案1】:

    你的理解是正确的。 funca 使用堆栈垃圾初始化。

    每次你说int a;,它都会创建一个新变量,与封闭作用域中类似命名的变量或调用堆栈更高层其他函数的变量无关。

    在你的理由中,你混淆了Scope and Extent。 c 使用lexical scoping,所以虽然main 的“extent”(或lifttime)是通过func 的执行而存在的,但它是一个完全不同的范围,所以它指的是一个完全不同的变量。

    请注意,“外部范围”通常是您外部的大括号,最外部的范围是文件级别。

    int a; // global
    void func(int a) {  // parameter
      int a;  // function local
      while (0) {
        int a;  // scoped in the 'while'
        if (true) { 
          int a;  // scoped in the 'if'
        }
      }
    }
    

    每个'a'变量shadows其他'a'在它上面。

    异常(可能是您混淆的根源)是声明为extern int a; 的变量。这个变量特指来自其他地方的变量(不同的翻译单元)。 external declaration 可用于获取您不期望的行为:

    外部变量也可以在函数内部声明。在这种情况下你必须使用 extern 关键字,否则编译器会认为它是一个局部变量的定义,它有不同的作用域、生命周期和初始值。此声明仅在函数内部可见。

    “堆栈垃圾”规则的例外是 static 和堆分配的变量是零初始化的(如果我没记错的话,这是由标准强制执行的)。

    还要注意“垃圾值”可能是 3。

    【讨论】:

    • 他的例子没有封闭范围!
    • @Lucas,我​​并不是要推断它确实如此。编辑澄清。
    • +1:非常完整的答案。我不认为你的意思是这样,但考虑到他的例子,这有点误导。
    【解决方案2】:

    您的预测结果是正确的,但您的推理并不完全正确。它永远不会在main 函数中引用变量a,因为mainfunc 的外部范围内不是。即使它存在于外部作用域中,它也会被内部作用域中的变量遮蔽。示例:

    int a = 3;
    printf("%d", a);
    {
        int a;
        printf ("%d", a);
    }
    

    将打印&lt;3&gt; &lt;junk value

    【讨论】:

      【解决方案3】:

      a 变量的作用域不同。你想象的输出是正确的。

      【讨论】:

        【解决方案4】:

        在您的情况下,您既没有外部作用域也没有内部作用域:您有两个局部作用域,它们仅在{} 分隔的块内持续存在。

        所以是的,在您的情况下,该函数内的 printf 将使用 func() 中定义的 a

        类似的情况,您实际上拥有一个全局范围变量,例如

        int a = 0;
        
        int main(void)
        {
          int a;
          printf("%d", a);
        }
        

        将产生相同的 junk 结果,因为新声明会影响全局声明。

        编译器不关心变量是否已经初始化,只关心使用最近的声明(在范围内最近)。

        【讨论】:

          【解决方案5】:

          在我的带有 gcc 3.4.2 的 Solaris 9 机器上:

          #include <stdio.h>
          
          void func(void) 
          { 
              int a; 
              printf ("func:%d ", a); 
              a=9;
          } 
          
          int main(int argc, char **argv) 
          { 
              int a = 3; 
              while(a--)
                  func(); 
              printf("main:%d\n", a); 
          } 
          

          输出:

          > ./a.out
          func:-12719276 func:9 func:9 main:-1
          

          “9”来自函数的前一个化身。这意味着在这个系统上,函数每次被调用时都映射到完全相同的堆栈帧,因此它清楚地显示了“剩余”垃圾效应。我们自己创建的。

          【讨论】:

          • 这是将 0xDEADBEEF 分配给变量以定位此类问题的原因之一 - 在调试器中,当您看到 value = DEADBEEF 的变量时,很明显您的数据中有剩余。
          猜你喜欢
          • 2013-02-15
          • 1970-01-01
          • 2013-05-10
          • 2014-07-14
          • 2022-01-12
          • 2014-03-02
          • 2023-03-29
          • 2014-10-25
          • 2013-10-14
          相关资源
          最近更新 更多