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

我有以下代码片段,我必须分析输出将是什么:

#include  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会受到赋值,而在main()体的printf() ,会打印在main()声明的a 。 但是,我不确定其余变量的行为。 这是未定义的行为还是实际上有意义?

int a = 1, b = 2, c = 3, d = 4; —>全局变量

 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` 

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

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

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

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

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

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

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

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

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

以下示例演示了这一点:

 #include  const char a[] = "a"; static const char b[] = "b"; void test(const char * arg) { const char c[] = "c1"; printf("1-. a=%sb=%sc=%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=%sb=%sc=%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=%sb=%sc=%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=%sb=%sc=%s arg=%s\n", a,b,c,arg); } printf("2+. a=%sb=%sc=%s arg=%s\n", a,b,c,arg); } printf("1++. a=%sb=%sc=%s arg=%s\n", a,b,c,arg); } int main(void) { test("arg"); return 0; } 

输出:

 1-. a=ab=bc=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 

这个输出实际上有意义。

在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