当我们可以用相同的代价得到一个全局变量时,静态局部变量有什么用处?

11
在C语言中,即使外部变量可以以相同的成本满足其目的(即二者都占用可执行文件的数据段中的存储空间),静态存储类的作用是什么?
我更喜欢使用外部变量。如果我想使外部变量的作用域限定在特定的文件中,则不会在其他地方声明该变量。相对于静态局部变量,全局变量具有更高的灵活性。
如果我们拥有变量的地址,那么可以在函数外部引用局部静态变量。局部静态变量的内存将位于数据段而不是函数的堆栈帧中,这是静态存储类带来的独特特点。
我只想知道静态存储类是否具有任何我不知道的微妙用途。

2
你有没有考虑作用域是第一个可能的解释呢?其次是保持私有性。静态可以做到这一点。 - Koushik Shetty
1
可能是在C程序中,“static”是什么意思?的重复问题。 - stijn
4
更大并不一定更好,有时限制反而是一件好事。 - unkulunkulu
@unkulunkulu:我同意有时候限制是一件好事,但灵活性总是更好的。 - Adi
"外部变量"也具有静态存储类。我想你的意思是,内部链接的用途是什么。 - M.M
显示剩余6条评论
6个回答

30
您写道全局变量具有“更好”的作用域,这是不正确的。它有更广泛的作用域,但更广泛并不一定更好。
如果需要标识符在更多地方可见,则更广泛的作用域可能是必需的,但通常情况下并非如此。更广泛的作用域意味着更容易出现错误。全局变量通过使程序状态难以查看来混淆例程的语义,并增加因未声明本地标识符和其他错误而导致的错误的概率。
特别是,具有外部链接的标识符将与其他库中的标识符冲突。考虑一下当您编写物理应用程序时,有一个名为acceleration的外部标识符,并且链接到具有外部标识符acceleration的物理库时会发生什么。程序将失败。因此,外部标识符通常是不良设计。
我们开发和维护复杂软件的能力存在重大限制,其中很多是人为错误。大多数编程语言语义都限制了语言以防止错误。通过原始计算机,您可以添加两个指针,垃圾堆栈指针,意外将float的字节加载到整数寄存器中等等。好的编程语言通过设计使这些错误难以发生。
在作用域规则帮助控制它们之前,全局变量是错误的主要来源。好的程序员限制标识符的作用域。

7

全局变量是可以从任何地方访问的,因此它是“全局”的。

静态局部变量具有本地范围。它是静态的,因此它的生命周期跨越应用程序的整个生命周期,但只能从本地作用域(无论该作用域是函数、块或文件)中访问。


如果我们有变量的地址,我们可以在函数外部引用局部静态变量。局部静态变量的内存将位于数据段而不是函数的堆栈帧中。难道我们不能这样做吗? - Adi
3
如果你拥有内存地址,那么你就可以访问它,但这是否适用于任何变量呢?即使是局部的非静态变量,你也可能从另一个线程中访问到其内存位置。编程语言提供了“静态”的概念,这样你就可以限制该变量的范围,而不是特定的内存位置。 - msam
@BillHicks 另外,文件作用域的 static 关键字允许您在文件级别拥有相同的变量名称,表示不同编译单元中的不同内存位置,而具有相同名称的非静态变量在文件作用域中共享相同的内存(这是 static 带来的额外功能)。 - msam

1
基本区别在于变量的作用域。
1)全局变量对整个项目都是全局的。比如说你的项目有10个不同的文件,那么所有10个文件都可以访问全局变量(查看如何使用extern)。
2)静态变量/函数只能被定义在函数/文件内部的函数/文件使用。它不能被项目中的任何其他文件使用。
然而,你可以通过传递变量的引用,在func2()中修改由func1()定义的静态变量。请参考下面的例子。
void func2(int *i)
{
    (*i)++;
}

void func1()
{
    static int i;

    i=1;
    printf("%d\n", i);
    func2(&i);
    printf("%d\n", i);  
}

int main()
{
    func1();
    return 0;
}

正如您在上面看到的,func1() 函数有一个无法直接被 func2() 操作的静态整型变量 static int i,但是如果您传递该变量的引用,则仍然可以像操作普通变量一样操作该变量。希望这能帮到您...

很遗憾,这并没有帮助到我,我已经知道了。我的问题是静态可以独特地提供哪些功能,而extern不能。 - Adi
使用static关键字可以限制函数仅在特定文件中使用... 而使用extern引用函数原型,您可以从任何其他文件访问在一个文件中定义的函数.....这是主要的。 - Kinjal Patel

0
首先,局部变量和全局变量的区别在于作用域:你只能从定义它们的块内部访问局部变量,而全局变量可以从任何地方访问。因此,在全局作用域中,你只能有一个给定名称的变量,但是在不同函数中可以有多个局部静态变量。
与静态全局变量相比,外部变量:是的,静态全局变量是局部于翻译单元(即定义它们的.c源文件)的。
因此,这里的主要关注点是作用域的概念,存储自然而然地从那里产生。

如果我们有变量的地址,我们可以在函数外部引用局部静态变量。局部静态变量的内存将位于数据段而不是函数的堆栈帧中。难道我们不能这样做吗? - Adi
2
如果我们有一个地址,我们可以访问 C 中的任何东西,即使它不是变量并且在代码中没有名称。所以是的。作用域是我们可以通过名称访问变量的地方,在这个意义上,作用域仅限于定义它的函数。关于内存部分,你是正确的,当然没有堆栈。 - unkulunkulu

0
你应该使用本地静态变量的原因是它的作用域,从而避免一些容易出错的情况,因为使用本地静态变量后,你将无法在定义它的函数之外引用它。

如果我们有变量的地址,我们可以在函数外部引用局部静态变量。局部静态变量的内存将位于数据段中,而不是函数的堆栈帧中。 - Adi
@BillHicks 不是的,地址不是一个变量。 - Matthew Read

-1
这是一个简短的程序,演示了它们之间的差异:
#include <stdio.h>

static int a=20;
void local()
{
   printf("%d,addr:%d \n", a, (void*)&a);
   a = 100;
}

int main()
{

      {
         static int a = 10;
         printf("%d,addr:%d \n", a, (void*)&a);
         local();
      }
      printf("%d addr:%d \n", a, (void*)&a);
}

输出:

10,addr:134518604   -- local static inside the braces
20,addr:134518600   -- this is referring the global static variable
100 addr:134518600  -- This is referring the global static variable which is outside of 
                       the braces.

这里花括号也很重要:如果在main()函数中没有花括号,则仅涉及本地静态变量。

这并没有解释为什么我们更喜欢局部静态变量而不是全局变量(尽管它开始通过展示local()如何修改全局变量a来解释)。 - Toby Speight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接