2014-01-17 41 views
3

我有下面的代码片段,我要分析的输出将是什么:声明的同名全球,本地和静态变量

#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()体中打印出在main()中声明的a。但是,我不确定其他变量的行为。这是不确定的行为还是它有意义?

+2

不合格的名称始终指最内层的封闭声明。 –

+1

我认为你的输出第2行有一个错字 - 它应该以'14'开头,而不是'15'。 –

回答

3

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` 

...

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

除非malloc分配,否则每个函数的变量都将放置在“堆栈”中。 而全局变量是“堆”。 我不确定,但如果你反汇编你的程序,静态值a会去堆栈 和治疗与PUSH和POP指令。

1

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

  • 顶级标识符:从声明点延伸到源程序文件
  • 在功能definiton
  • 形式参数的末尾:延伸到函数体
  • 正式结束在函数原型
  • 块(本地)标识符参数:延伸至块的末端
  • 语句标签
  • 预处理器宏

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

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

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

考虑到这一点,在你的代码,当地acmain()隐藏全局ac,并af()隐藏全球a。所有其他引用都在操纵全局变量。

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 
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