声明与global,local和static同名的变量

时间:2014-01-17 10:33:52

标签: c variables declaration

我有以下代码片段,我必须分析输出结果:

#include <stdio.h>

  void f(int d);

  int a = 1, b = 2, c = 3, d = 4;

  int main(){
    int a = 5, c = 6;
    f(a);
    f(b);
    f(c);
    printf("%d %d %d %d\n",a,b,c,d);
    return 0;
  }

  void f(int d){
    static int a = 0;
    a = a + 7;
    b = a + d;
    c++;
    d--;
    printf("%d %d %d %d\n",a,b,c,d);
  }

我得到的输出如下:

7 12 4 4  
15 26 5 11  
21 27 6 5  
5 27 6 4  

这真让我困惑。我注意到在所有3个函数调用中,全局声明的a都会受到分配的影响,并且printf()来自main()的{​​{1}}正在打印a中声明的main() 。但是,我不确定其余变量的行为。这是未定义的行为还是实际上有意义?

5 个答案:

答案 0 :(得分:3)

int a = 1, b = 2, c = 3, d = 4; ---&gt;全局变量

int main(){
    int a = 5, c = 6;         ---> Shadows the global `a` and `c`

...

void f(int d){
    static int a = 0;         ---> local static variable visible only inside `f`

...

答案 1 :(得分:2)

这与C的标识符范围有关。声明的范围是C程序的区域,该声明在该区域中可见。有六个范围:

  • 顶级标识符:从声明点延伸到源程序文件的末尾
  • 函数定义中的形式参数:延伸到函数体的末尾
  • 函数原型中的形式参数
  • 块(本地)标识符:一直延伸到块的末尾
  • 声明标签
  • 预处理器宏

您的程序中发生的事情称为名称重载 - 同一标识符一次可能与多个程序实体相关联的情况。 C中有5个重载类(aka名称空间):

  • 预处理程序宏名称
  • 声明标签
  • 结构,联合和枚举标记
  • 组件名称
  • 其他名称

在C中,块开头的声明可以隐藏块外的声明。 对于一个隐藏另一个声明的声明,声明的标识符必须相同,必须属于同一个重载类,并且必须在两个不同的作用域中声明,其中一个包含另一个。

考虑到这一点,在您的代码中,本地ac隐藏a中的全局cmain()以及a f()隐藏了全局a。所有其他引用都在操纵全局变量。

答案 2 :(得分:1)

 void f(int d){
     **static int a = 0;**
     a = a + 7;
     b = a + d;
     c++;
     d--;
     printf("%d %d %d %d\n",a,b,c,d);
   }

你说的是全局 int a 和全局无效函数 f 但你也声明了静态变量 每当函数调用时,函数就是引用函数的变量。 如果你想避免这个问题,你应该创建一个全局变量的指针,并引用一个指向地址的值全局变量。 如您所知,静态变量保持其最后一个值直到程序结束。

除非由malloc分配,否则每个函数的变量都将完全放在“Stack”中。 全局变量是“堆”。 我不确定,但是如果你反汇编你的程序,静态值将会叠加 并用PUSH和POP指令处理。

答案 3 :(得分:0)

在C / C ++中,给定范围内的标识符从声明之后的开始影响外部范围中的标识符

以下示例演示了这一点:

#include <stdio.h>

const char a[] = "a";

static const char b[] = "b";

void test(const char * arg)
{
   const char c[] = "c1";
   printf("1-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   const char a[] = "a1";
   static const char b[] = "b1";
   // arg is present in this scope, we can't redeclare it
   printf("1+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   {
      const char a[] = "a2";
      const char b[] = "b2";
      const char arg[] = "arg2";
      const char c[] = "c2";
      printf("2-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
      {
         static const char a[] = "a3";
         const char b[] = "b3";
         static char arg[] = "arg3";
         static const char c[] = "c3";
         printf("3. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
      }
      printf("2+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   }
   printf("1++. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}

int main(void)
{
   test("arg");
   return 0;
}

输出:

1-. a=a b=b c=c1 arg=arg
1+. a=a1 b=b1 c=c1 arg=arg
2-. a=a2 b=b2 c=c2 arg=arg2
3. a=a3 b=b3 c=c3 arg=arg3
2+. a=a2 b=b2 c=c2 arg=arg2
1++. a=a1 b=b1 c=c1 arg=arg

答案 4 :(得分:0)

这个输出实际上是有道理的。

在C / C ++中,给定范围内的标识符优先于外部范围中的标识符。在这种情况下,在函数main中,变量a和c将用作局部变量,其余b和d用作全局变量。类似地,在函数void f(int d)中,d是传递的参数,每当调用函数时,a将用作静态,b和c将用作全局变量。 因此将计算输出。

但是您显示的输出不正确。正确的输出必须是:

7 12 4 4 14 26 5 11 21 27 6 5 5 27 6 4