C静态范围语义


C static scope semantics

我正在学习C,并且遇到了这个程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int a, b, c = 0;
void prtFun (void);
int main ()
{
    static int a = 1; /* line 1 */
    prtFun();
    a += 1;
    prtFun();
    printf ("n %d %d" , a, b) ;
}

void prtFun (void)
{
    static int a = 2; /* line 2 */
    int b = 1;
    a += ++b;
    printf (" n %d %d" , a, b);
}

输出如下:

1
2
3
4 2
6 2
2 0

它给出了以下解释

"'a'和'b'是全局变量。prtfun()还具有"a"和"b"作为局部变量。局部变量隐藏全局变量(参见C中的作用域规则)。当第一次调用prtfun()时,本地"b"变为2,本地"a"变为4。第二次调用prtfun()时,使用本地静态"a"的同一个实例,并创建"b"的新实例,因为"a"是静态的,"b"是非静态的。所以"b"再次变为2,"a"变为6。main()还具有自己的名为"a"的局部静态变量,该变量在main中隐藏全局"a"。main()中的printf()语句访问本地"a"并打印其值。printf()语句访问全局"b",因为main中没有名为"b"的局部变量。此外,静态和全局int变量的默认值为0。这就是为什么main()中的printf语句将0作为b的值打印出来的原因。"

我的印象是C中的静态变量只声明一次,具有全局范围,并且所有全局变量都是隐式静态的。那么,在给定全局变量隐式声明的全局范围或main中的显式声明的全局范围的情况下,如何正确地在不同的范围内重新声明这些静态变量呢?如果一个静态变量在内存中只有一个位置,并且它有一个全局范围,那么这个程序中如何有具有相同名称的块特定静态变量?

谢谢


我会尽可能简洁地帮助你。在C语言中,以下陈述是不正确的:

  • "所有全局变量都是隐式静态的"
  • "静态变量在内存中只有一个位置"

全局变量可以是静态的或非静态的(常规)。不同之处在于,常规全局变量可以被其他翻译单元(简而言之,C文件)使用,而静态变量则不能。

我给你举个例子。假设您有两个C文件,A.C和B.C。在公元前:

1
2
int my_global_var;
static int a_static_var;

在公元前:

1
2
3
4
extern int my_global_var;
static int a_static_var;

int main() { /* ... */ }

您可以使用这两个C文件构建一个程序,这样[假设您使用的是Linux]:

1
2
3
gcc -c a.c
gcc -c b.c
gcc -o prog a.o b.o

现在,变量my_global_var在两个文件中都是相同的,但它在a.o翻译单元中被实例化(b.c将其视为外部变量)。虽然变量a_static_var不是唯一的。每个翻译单元都有自己的a_static_var变量:它们完全不相关。

回到您的示例,静态变量也可以有函数范围:在这种情况下,在不同函数中定义的静态变量是完全不相关的,这与单独翻译单元中的全局静态变量是不相关的。在你的例子中,你可以把两个静态的a变量想象成它们被称为__main_a__prtFun_b。实际上,这与编译程序时在引擎盖下发生的情况非常接近。

现在,为了完成这幅图,有一个规则允许您定义本地(静态或非静态)变量,即使这将隐藏用相同名称定义的全局变量。因此,在prtFun()中,例如,当您访问b时,您访问的是本地非静态变量;当您访问a时,您访问的是本地静态a变量。对于main()也是如此。在任何情况下,您的代码都不会触及全局a, b, c变量。

希望我能帮上忙。


尽管vvartchev已经提供了一个很好的解释,我还是想加上一两件事…

大多数书籍、教程等都使用静态的,如代码中所示,以在多个函数调用上保留局部变量的值。然而,这只是静电的一个用途,而且——在我看来——更无用的用途之一。

让我们重温一下这句话

Global variables can be static or non-static (regular). The difference is that regular global variables can be used by other translation units (briefly, C files), while the static variables cannot.

静态的这种用法没有在代码中演示,但实际上非常有用,因为它本质上意味着您可以定义变量(和函数!)它们是"私有的",并且从另一个C文件中永远看不到。这允许将哪些函数和变量与其他模块完全分离,哪些模块不可见。

我强烈建议将所有函数定义为静态函数,而不应从另一个C文件中调用该函数。

我觉得静态的这方面经常被忽视,而且每个人似乎都只关注愚蠢的"嘿,你可以通过多个函数调用来保持这个值"。尽管这通常是一个非常糟糕的主意,因为这样你就有了一个函数,每次你调用它时它的行为都是不同的。