C语言中的“静态”是什么意思?

What does "static" mean in C?

提问人: 提问时间:2/21/2009 最后编辑:jww 更新时间:6/26/2023 访问量:1157794

问:

我在 C 代码的不同地方看到过这个词;这是否类似于 C# 中的静态函数/类(实现在对象之间共享)?static

C 语法 static

评论

9赞 Palec 2/6/2015
相关新闻: 静态(关键字) @ Wikipedia
42赞 Palec 5/22/2017
@Lundin,从标题末尾删除“in a C program”的原因是什么?在存在标签 c 的情况下,它有点多余,但它让我可以更快地查看分类,而无需检查标签。当我从可能包含有关其他语言的问题(例如静态或 Google 搜索)的方向提出问题时,这种冗余非常舒服。
7赞 Ciro Santilli OurBigBook.com 6/17/2017
@Lundin 我更喜欢在标题中保留“C”,因为 SO 只在标题后面附加一个标签(最常见的?如果有一天“语法”比 C 语言有更多的问题(因为它是跨语言的东西)怎么办?我宁愿使用显式行为:-)编辑:啊,但有一个元问题说:meta.stackexchange.com/questions/19190/......
3赞 nalzok 8/27/2017
这是我在Quora上找到的解释。绝对值得一读!
1赞 5/15/2020
静态的存储持续时间是直到程序结束,而不是直到作用域结束。

答:

1853赞 Eli Bendersky 2/21/2009 #1
  1. 函数中的静态变量在调用之间保持其值。
  2. 静态全局变量或函数仅在声明它的文件中“可见”

(1)如果你是新手,是更陌生的话题,所以这里有一个例子:

#include <stdio.h>

void foo()
{
    int a = 10;
    static int sa = 10;

    a += 5;
    sa += 5;

    printf("a = %d, sa = %d\n", a, sa);
}


int main()
{
    int i;

    for (i = 0; i < 10; ++i)
        foo();
}

这将打印:

a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60

这对于函数需要在调用之间保持某些状态并且您不想使用全局变量的情况很有用。但是,请注意,应该非常谨慎地使用此功能 - 它使您的代码不是线程安全的并且更难理解。

(2) 作为“访问控制”功能被广泛使用。如果你有一个实现某些功能的 .c 文件,它通常只向用户公开几个“公共”功能。它的其余功能应该被制作,这样用户将无法访问它们。这是封装,是一个很好的做法。static

引用维基百科

在 C 编程语言中,静态 与全局变量一起使用,并且 函数将其范围设置为 包含文件。在局部变量中, static 用于存储变量 在静态分配的内存中 而不是自动分配的 记忆。虽然语言没有 规定实现 静态分配的内存类型 内存通常保留在数据中 编译时程序的段 时间,而自动 分配的内存通常 作为瞬态调用堆栈实现。

为了回答你的第二个问题,它不像在 C# 中。

但是,在 C++ 中,也用于定义类属性(在同一类的所有对象之间共享)和方法。在 C 语言中没有类,因此此功能无关紧要。static

评论

188赞 Eli Bendersky 2/21/2009
Pax,OP 不知道静态,所以你建议让他陷入编译单元和文件之间的区别?:-)
150赞 Eli Bendersky 2/21/2009
编译单元是编译器看到的单个文件。您的 .c 文件可能包含其他 .c 文件,但在预处理器整理出包含内容后,编译器最终只看到一个“编译单元”。
91赞 Eli Bendersky 2/16/2010
@robUK:编译器甚至不知道 .h 文件——这些文件被合并到预处理器中的 .c 文件中。所以是的,你可以说 .c 文件,包括所有标头,是一个单一的编译单元。
11赞 peterph 2/28/2014
@TonyD也许令人困惑,但这就是编译的工作方式。它通常可能是一堆头文件,但魔鬼总是在不典型的东西中。.c
11赞 Miles Rout 4/10/2014
@TonyD 编译器进行编译。预处理器进行预处理。将工具链称为“编译器”不会改变它是什么或它的作用。
18赞 OscarRyz 2/21/2009 #2

来自维基百科:

在 C 编程语言中,static 与全局变量和函数一起使用,以将其范围设置为包含文件。在局部变量中,static 用于将变量存储在静态分配的内存中,而不是自动分配的内存中。虽然该语言不规定任何一种类型的内存的实现,但静态分配的内存通常在编译时保留在程序的数据段中,而自动分配的内存通常作为瞬态调用堆栈实现。

评论

0赞 Jens 10/10/2020
维基百科最糟糕的时候。静态设置链接,而不是作用域。了解其中的区别至关重要。
4赞 natiiix 1/2/2021
@Jens 没有人会问问题,会知道这意味着什么。但是,范围的概念几乎是所有语言的通用概念,因此任何人都应该能够根据此描述大致理解如何影响对象。出于同样的原因,它提到了“包含文件”而不是“当前编译单元”。staticlinkagestatic
0赞 Jens 1/2/2021
@natiiix 链接不是范围。 不设置范围。即使是“包含文件”也是错误的,因为作用域只从声明器的末尾开始,而不是从文件的开头开始。引用的维基百科条目具有误导性,会让特朗普脸红。static
2赞 natiiix 1/2/2021
@Jens 不过,这并不重要。出于所有意图和目的,使全局变量成为文件的本地变量,并将它们从真正的全局范围中删除。当一个简单的问题被问到一个简单、直接的答案时,没有必要展示花哨的术语。当然,这并不完全正确,但它可以帮助每个人理解总体思路,这比一些术语的细微差别更重要。static
11赞 Jonathan Adelson 2/21/2009 #3

如果在函数 static 中声明变量,则其值不会存储在函数调用堆栈中,并且在再次调用该函数时仍然可用。

如果声明全局变量为 static,则其作用域将限制在声明该变量的文件中。这比常规全局稍微安全一些,常规全局全局可以在整个程序中读取和修改。

19赞 m-sharp 2/21/2009 #4

static在不同的语境中意味着不同的东西。

  1. 您可以在 C 函数中声明静态变量。此变量仅在函数中可见,但它的行为类似于全局变量,因为它只初始化一次并保留其值。在此示例中,每次调用它时,都会打印一个递增的数字。静态变量仅初始化一次。foo()

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. 静态的另一个用途是当您在 .c 文件中实现函数或全局变量,但不希望其符号在文件生成的外部可见。例如.obj

    static void foo() { ... }
    
204赞 cmcginty 2/21/2009 #5

简短的回答......这要视情况而定。

  1. 静态定义的局部变量在函数调用之间不会丢失其值。换句话说,它们是全局变量,但范围限定为定义它们的局部函数。

  2. 静态全局变量在定义它们的 C 文件之外不可见。

  3. 静态函数在定义它们的 C 文件之外不可见。

评论

10赞 user1599964 1/20/2013
那么“静态函数”和“私有函数”是不是一回事呢?同样,“静态全局变量”和“私有全局变量”是一回事吗?
47赞 chris 2/14/2013
这是关于C的。C 中没有私有/公共。
33赞 Ciro Santilli OurBigBook.com 4/23/2015
@user1599964虽然 C 中没有,但您的类比很好:静态使给定文件的内容“私有”。C 中的文件通常映射到 C++ 中的类。private
41赞 Artyom 2/21/2009 #6

这取决于:

int foo()
{
   static int x;
   return ++x;
}

该函数将返回 1、2、3 等,---变量不在堆栈上。

交流:

static int foo()
{
}

这意味着此函数仅在此文件中具有作用域。因此,a.c 和 b.c 可以有不同的 s,并且 foo 不会暴露给共享对象。因此,如果您在 a.c 中定义了 foo,则无法从任何其他地方访问它。foo()b.c

在大多数 C 库中,所有“私有”函数都是静态的,而大多数“公共”函数则不是。

评论

20赞 RoundPi 11/5/2012
+1 表示提及 x 不在堆栈或堆上。它位于静态内存空间上。
1赞 Yousha Aleayoub 3/12/2018
@Gob00st静态内存空间?你是说“数据段”......?
0赞 Ekrem Dinçel 11/11/2020
@YoushaAleayoub 看到这个这个
0赞 sekomer 12/21/2020
In most C libraries all "private" functions are static and most "public" are not.你好,我有一个关于这个问题的问题,你说,我想知道函数如何表现为公共的moststatic
1赞 Eljay 12/24/2020
@Sekomer • 如果静态函数指针作为另一个函数的函数指针返回值“转义”,或者通过结构中的成员变量设置为函数指针。
5赞 Gary 2/21/2009 #7

在 C 语言中,static 有两个含义,具体取决于其使用范围。在全局范围内,当在文件级别声明对象时,这意味着该对象仅在该文件中可见。

在任何其他作用域中,它声明一个对象,该对象将在输入特定作用域的不同时间之间保留其值。例如,如果在过程中对 int 进行删除:

void procedure(void)
{
   static int i = 0;

   i++;
}

“I”的值在第一次调用过程时初始化为零,并在以后每次调用该过程时保留该值。如果打印“i”,它将输出 0、1、2、3、...

5赞 ant2009 3/11/2009 #8

如果在文件中声明此项:mytest.c

static int my_variable;

那么这个变量只能从这个文件中看到。该变量不能导出到其他任何位置。

如果在函数内部声明,则每次调用该函数时,变量的值将保留其值。

静态函数不能从文件外部导出。因此,在文件中,如果将函数和变量声明为静态,则将其隐藏。*.c

85赞 Ciro Santilli OurBigBook.com 1/15/2013 #9

多文件变量作用域示例

在这里,我说明了静态如何影响跨多个文件的函数定义范围。

交流电

#include <stdio.h>

/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/

/* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */
/*int i;*/

/* OK: extern. Will use the one in main. */
extern int i;

/* OK: only visible to this file. */
static int si = 0;

void a() {
    i++;
    si++;
    puts("a()");
    printf("i = %d\n", i);
    printf("si = %d\n", si);
    puts("");
}

main.c

#include <stdio.h>

int i = 0;
static int si = 0;

void a();    

void m() {
    i++;
    si++;
    puts("m()");
    printf("i = %d\n", i);
    printf("si = %d\n", si);
    puts("");
}

int main() {
    m();
    m();
    a();
    a();
    return 0;
}

GitHub 上游

编译并运行:

gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o

输出:

m()
i = 1
si = 1

m()
i = 2
si = 2

a()
i = 3
si = 1

a()
i = 4
si = 2

解释

  • 有两个单独的变量 ,每个文件一个si
  • 有一个共享变量i

像往常一样,范围越小越好,所以如果可以的话,一定要声明变量。static

在 C 编程中,文件通常用于表示“类”,变量表示类的私有静态成员。static

标准对此有何规定

C99 N1256 草案 6.7.1 “存储类说明符”说这是一个“存储类说明符”。static

6.2.2/3 “标识符的联系”意味着:staticinternal linkage

如果对象或函数的文件范围标识符的声明包含存储类说明符 static,则该标识符具有内部链接。

6.2.2/2 表示其行为类似于我们的示例:internal linkage

在构成整个程序的翻译单元和库集合中,具有外部链接的特定标识符的每个声明都表示相同的对象或功能。在一个翻译单元中,每个具有内部链接的标识符声明都表示相同的对象或功能。

其中“翻译单元是预处理后的源文件。

GCC 如何为 ELF (Linux) 实现它?

与绑定。STB_LOCAL

如果我们编译:

int i = 0;
static int si = 0;

并用以下命令拆卸符号表:

readelf -s main.o

输出包含:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    4 si
 10: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    4 i

因此,绑定是它们之间唯一的显着区别。 只是它们在部分中的偏移量,因此我们预计它会有所不同。Value.bss

STB_LOCAL记录在 ELF 规范中,http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html

STB_LOCAL 本地符号在包含其定义的对象文件之外不可见。同名的本地符号可以存在于多个文件中,而不会相互干扰

这使它成为代表 .static

没有 static 的变量是 ,规范说:STB_GLOBAL

当链接编辑器组合多个可重定位的对象文件时,它不允许对具有相同名称的STB_GLOBAL符号进行多个定义。

这与多个非静态定义上的链接错误一致。

如果我们用 来启动优化,则符号将从符号表中完全删除:无论如何都不能从外部使用。TODO在没有优化的情况下,为什么要在符号表上保留静态变量?它们可以用于任何事情吗?也许是为了调试。-O3si

另请参阅

C++ 匿名命名空间

在 C++ 中,您可能希望使用匿名命名空间而不是静态命名空间,这样可以实现类似的效果,但会进一步隐藏类型定义:未命名/匿名命名空间与静态函数

288赞 dreamlax 5/1/2013 #10

这里没有介绍另一个用法,那就是作为数组类型声明的一部分,作为函数的参数:

int someFunction(char arg[static 10])
{
    ...
}

在此上下文中,这指定传递给此函数的参数必须是包含至少 10 个元素的类型数组。有关更多信息,请在此处查看我的问题。char

评论

5赞 suprjami 9/29/2015
我不认为 C 有数组参数?莱纳斯·托瓦兹(Linus Torvalds)愤怒地咆哮着人们这样做。
22赞 dreamlax 9/30/2015
@jamieb:C 没有数组参数,但这种特定的语法意味着函数期望 through to 具有值(这也意味着该函数不接受 null 指针)。编译器可以以某种方式利用这些信息进行优化,静态分析器可以利用这些信息来确保函数永远不会被赋予空指针(或者,如果它能分辨出,则表示元素少于指定元素的数组)。arg[0]arg[9]
26赞 Happy Green Kid Naps 12/23/2015
@Qix -- 这是 C99 中赋予的一个新的重载含义。它已经有十五年的历史了,但并不是所有的编译器编写者都接受了 C99 的所有特性——所以 C99 作为一个整体在很大程度上仍然是未知的。static
1赞 RastaJedi 5/1/2016
@suprjami 我不是 100% 确定你所说的“数组参数”是什么意思,但如果你的意思是,那么这就是 VLA(可变长度数组),它是在 C99 中添加的。你是这个意思吗?int arr[n];
0赞 Nikolai Ehrhardt 3/20/2022
这是否意味着,我不能将任何 char* 传递给这个函数,因为没有人知道它是否可以增加 10 ...我怀疑你的答案,尽管它很有趣。
1赞 Jonathon 3/23/2014 #11

静态变量值在不同的函数调用之间持续存在,其作用域仅限于本地块 静态 var 始终以值 0 初始化

4赞 Starhowl 5/1/2014 #12

需要注意的是,函数中的静态变量在第一次进入该函数时被初始化,即使在调用完成后也会持续存在;在递归函数的情况下,静态变量只初始化一次,并且在所有递归调用中,甚至在函数调用完成后也会持续存在。

如果变量是在函数外部创建的,则意味着程序员只能在已声明变量的源文件中使用该变量。

6赞 Yagel 12/22/2014 #13

静态变量是可以在函数中使用的特殊变量,它在调用之间保存数据,并且在调用之间不会删除数据。例如:

void func(void) {
    static int count; // If you don't declare its value, it is initialized with zero
    printf("%d, ", count);
    ++count;
}

int main(void) {
    while(true) {
        func();
    }
    return 0;
}

输出:

0, 1, 2, 3, 4, 5, ...

4赞 Sahil Manchanda 3/22/2015 #14

C 语言中的静态变量具有程序的生存期。

如果在函数中定义,则它们具有局部作用域,即只能在这些函数内部访问它们。静态变量的值在函数调用之间保留。

例如:

void function()
{
    static int var = 1;
    var++;
    printf("%d", var);
}

int main()
{
    function(); // Call 1
    function(); // Call 2
}

在上面的程序中,是存储在数据段中的。它的生命周期是整个 C 程序。var

函数调用 1 后,变为 2。函数调用 2 后,变为 3。varvar

的值在函数调用之间不会被销毁。var

如果介于非静态变量和局部变量之间,它将存储在 C 程序的堆栈段中。由于函数的堆栈帧在函数返回后被销毁,因此 的值也被销毁。varvar

初始化的静态变量存储在 C 程序的数据段中,而未初始化的静态变量存储在 BSS 段中。

关于静态的另一个信息:如果一个变量是全局的和静态的,则它具有 C 程序的生命周期,但它具有文件范围。它仅在该文件中可见。

要尝试此操作,请执行以下操作:

文件1.c

static int x;

int main()
{
    printf("Accessing in same file%d", x):
}

文件2.c

    extern int x;
    func()
    {
        printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
    }

run gcc -c file1.c

gcc -c file2.c

现在尝试使用以下方法链接它们:

gcc -o output file1.o file2.o

这将给出链接器错误,因为 x 的文件范围为 file1.c,并且链接器无法解析对 file2.c 中使用的变量 x 的引用。

引用:

  1. http://en.wikipedia.org/wiki/Translation_unit_(编程)
  2. http://en.wikipedia.org/wiki/Call_stack

评论

0赞 Eames 11/8/2017
我知道数据是持久的,这意味着每次调用函数后都不会丢失,但为什么每次都不将值改回 1static int var = 1;
11赞 jigglypuff 3/31/2016 #15

我不想回答一个老问题,但我认为没有人提到K&R在“C编程语言”的A4.1节中是如何解释它的。

简而言之,静态一词有两个含义

  1. 静态是两个存储类之一(另一个是 自动)。静态对象在调用之间保持其值。在所有块之外声明的对象始终是静态的,不能自动进行。
  2. 但是,当关键字(大力强调它被用于 code 作为关键字)与声明一起使用,它为该对象提供内部链接,因此它只能在该翻译单元中使用。但是,如果在函数中使用关键字,则会更改对象的存储类(无论如何,该对象仅在该函数中可见)。静态的对立面是关键字,它为对象提供外部链接。staticextern

Peter Van Der Linden 在“Expert C Programming”中给出了这两个含义:

  • 在函数内部,在调用之间保留其值。
  • 在函数级别,仅在此文件中可见。

评论

0赞 Jens 6/1/2018
还有第三个存储类,寄存器。有些人还为malloc和朋友返回的存储分配了第四个存储类。
0赞 GermanNerd 7/16/2019
@Jens 'register' 只是对编译器的提示;寄存器存储不能从 C 源内部强制执行。所以我不会认为它是一个存储类。
2赞 Jens 7/17/2019
@GermanNerd 恐怕 ISO C 标准不同意您的观点,因为它清楚地提出了一个存储类说明符(C99 6.7.1 存储类说明符)。它不仅仅是一个提示,例如,无论编译器是否分配寄存器,您都不能将 address-of 运算符应用于具有存储类的对象。register&register
0赞 GermanNerd 7/17/2019
@Jens 谢谢你提醒我 &.我可能做了太多的C++.....无论如何,虽然“register”是一个存储类说明符,但实际上编译器可能会为(无用的)“auto”说明符创建与“register”说明符相同的机器代码。所以唯一剩下的就是源代码级别的限制,即不能取地址。顺便说一句,这个小讨论让我在 Netbeans 中发现了一个错误;自从我最近一次更新以来,它在新的 C 项目上默认为 g++ 工具链!
30赞 PMar 4/27/2016 #16

人们一直说 C 语言中的“静态”有两个含义。我提供了一种另一种查看它的方式,赋予它一个单一的含义:

  • 将“静态”应用于项目会强制该项目具有两个属性:(a) 它在当前范围之外不可见;(b) 它是持久的。

它似乎有两个含义的原因是,在 C 中,可以应用“static”的每个项目都已经具有这两个属性之一,因此似乎该特定用法仅涉及另一个。

例如,考虑变量。在函数外部声明的变量已经具有持久性(在数据段中),因此应用“static”只能使它们在当前作用域(编译单元)之外不可见。相反,在函数内部声明的变量在当前作用域(函数)之外已经不可见,因此应用“static”只能使它们持久化。

将“静态”应用于函数就像将其应用于全局变量一样——代码必须是持久的(至少在语言中),因此只能更改可见性。

注意:这些注释仅适用于 C。在 C++ 中,将“static”应用于类方法确实赋予了关键字不同的含义。同样,对于 C99 数组参数扩展。

评论

1赞 Jens 7/9/2019
你的(a)充其量是多余的。任何变量在其作用域之外都是可见的。这就是范围的定义。你的意思在C标准中称为链接。 提供与标识符的内部链接static
1赞 Jonny Kong 6/3/2018 #17

有 2 种情况:

(1)声明的局部变量:在数据段而不是堆栈中分配。当您再次调用该函数时,其值将保留。static

(2)声明的全局变量或函数:在编译单元之外不可见(即链接时是符号表中的局部符号)。static

-4赞 Makdia Hussain 2/13/2019 #18

在 C 编程中,是一个保留关键字,它控制生存期和可见性。如果我们在函数中将一个变量声明为静态变量,那么它只会在整个函数中可见。在这种用法中,此静态变量的生存期将在函数调用时开始,并在执行该函数后销毁。您可以看到以下示例:static

#include<stdio.h> 
int counterFunction() 
{ 
  static int count = 0; 
  count++; 
  return count; 
} 

int main() 
{ 
  printf("First Counter Output = %d\n", counterFunction()); 
  printf("Second Counter Output = %d ", counterFunction()); 
  return 0; 
}

上面的程序将给我们这个输出:

First Counter Output = 1 
Second Counter Output = 1 

因为一旦我们调用该函数,它就会初始化 .当我们执行时,它将销毁 count 变量。count = 0counterFunction

评论

4赞 GermanNerd 7/16/2019
>上面的程序将给我们这个输出: 第一个计数器输出 = 1 第二个计数器输出 = 1 < 不正确。静态变量仅初始化一次。因此,输出将是 1,然后是 2,依此类推。
1赞 sekomer 12/21/2020
全局变量和静态变量被初始化为 ,你不应该在每次函数调用中将它们重新赋值为零。0
0赞 era5tone 2/12/2020 #19

静态变量具有一个属性,即使它们超出了其范围,也可以保留其值!因此,静态变量在其先前的作用域中保留其先前的值,并且不会在新作用域中再次初始化。

例如,看看这个—— 当程序运行时,静态 int 变量保留在内存中。当声明变量的函数调用结束时,普通变量或自动变量将被销毁。

#include<stdio.h> 
int fun() 
{ 
  static int count = 0; 
  count++; 
  return count; 
} 

int main() 
{ 
  printf("%d ", fun()); 
  printf("%d ", fun()); 
  return 0; 
}

这将输出:1 2

由于 1 保留在内存中,因为它被声明为静态

静态变量(如全局变量)如果未显式初始化,则初始化为 0。例如,在下面的程序中,x 的值被打印为 0,而 y 的值是垃圾。有关更多详细信息,请参阅此处。

#include <stdio.h> 
int main() 
{ 
    static int x; 
    int y; 
    printf("%d \n %d", x, y); 
}

这将输出:0 [some_garbage_value]

这些是我发现的主要问题,上面没有为新手解释过!

7赞 Chris Bao 7/27/2022 #20

分享我对这一点的了解。

在 C 中是一个声明说明符,它分为三类:static

  • 存储类:有四个类:auto、、extern 和 register。static
  • 类型限定符:如关键字:const、volatile 等。
  • 类型说明符:如关键字:void、char、short、int 等。

存储类也是如此。它将确定 C 程序中每个变量的以下三个属性。static

  • 存储持续时间:表示为变量分配内存和释放内存的时间。只要程序正在运行,具有存储持续时间的变量就会保持在同一内存位置。static
  • 作用域:表示程序文本中可以访问变量的部分。静态变量具有文件作用域,而不是块作用域
  • 链接:表示变量可以被程序的不同部分(或文件)共享的程度。如果在块内声明了静态变量,则它没有链接。如果静态变量在块外部声明,则它具有内部链接。内部链接使其可在单个文件中访问。

存储类对变量的影响不同,具体取决于变量是在块外部还是在块内部声明。需要逐案考虑。static

1赞 Thema Guishard 6/4/2023 #21

静态变量的作用域仅限于声明静态变量的文件。这也适用于静态函数。

但是,函数中声明的静态变量的作用域是不同的。它仅限于函数,如非静态变量,但它在对该函数的多次调用中保留其值。