【问题标题】:C static scope semanticsC 静态范围语义
【发布时间】:2019-05-27 09:20:21
【问题描述】:

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

#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);
}

输出如下:

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 中的显式声明的全局范围的情况下,如何在不同的范围内重新声明这些静态变量是正确的?如果静态变量在内存中只有一个位置,并且它具有全局范围,那么该程序中如何存在同名的块特定静态变量?

谢谢

【问题讨论】:

  • mainprtFun 中的两个static int a 变量是两个不同的 变量,它们恰好是同名的
  • 请注意,对于全局定义int a, b, c = 0;,您只需将c 显式初始化为零,而不是其他的。但是,C 被指定为“零初始化”所有全局(但未初始化)变量,因此无论如何它们都变为零。
  • static 是一个存储类说明符,它定义了对象的生命周期,但除了极少数例外,不会影响或改变本地或全局变量的标准作用域规则。跨度>
  • 没有“静态范围”这样的东西。范围是关于名称的可见性。 static存储持续时间。这两个概念是正交的。
  • static 变量的生命周期是整个程序,当你“第一次调用函数”时它不会“变成”什么东西。当你称它为 agfain 时,它肯定不会成为某种东西。

标签: c


【解决方案1】:

我会尽量做到简洁,为您提供帮助。 以下陈述在 C 中完全正确:

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

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

让我举个例子。假设您有两个 C 文件,a.c 和 b.c。 在交流中:

int my_global_var;
static int a_static_var;

在公元前:

extern int my_global_var;
static int a_static_var;

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

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

gcc -c a.c
gcc -c b.c
gcc -o prog a.o b.o

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

回到你的例子,静态变量也可以有函数作用域:在这种情况下,不同函数内部定义的静态变量是完全不相关的,与全局相同单独翻译单元内的静态变量是不相关的。在您的情况下,您可以考虑两个静态 a 变量,因为它们被称为 __main_a__prtFun_b。这实际上与编译程序时幕后发生的情况非常接近。

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

希望我对您有所帮助。

【讨论】:

    【解决方案2】:

    尽管 vvaltchev 已经提供了很好的解释,我还是想补充一两件事...

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

    让我们重温一下这句话

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

    静态的这种用法没有在您的代码中演示,但确实非常有用,因为它本质上意味着您可以定义“私有”的变量(和函数!),并且永远不会从另一个 c 文件中看到.这允许干净地分离哪些函数和变量应该对其他模块可见,哪些不应该。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-12
      • 2011-03-06
      • 1970-01-01
      相关资源
      最近更新 更多