C中“static”是什么意思?

我已经看到了在C代码中用于不同地方的static词。 这就像在C#中的静态函数/类(其中的实现共享对象)?

  1. 函数内部的静态variables在调用之间保持其值。
  2. 一个静态的全局variables或者一个函数只在它声明的文件中被“看到”

(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 

这对于函数需要在调用之间保持某种状态的情况非常有用,而您不想使用全局variables。 但是要小心,这个特性应该非常less用 – 这使得你的代码不是线程安全的,而且更难理解。

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

引用维基百科 :

在C编程语言中,static与全局variables和函数一起使用来将它们的作用域设置为包含文件。 在局部variables中,static用于将variables存储在静态分配的内存中,而不是自动分配的内存。 尽pipe语言并不指定任何一种types的内存的实现,但是静态分配的内存通常在编译时被保留在程序的数据段中,而自动分配的内存通常被实现为临时调用栈。

看到这里和这里的更多细节。

而要回答你的第二个问题,这不像在C#中。

然而,在C ++中, static也用于定义类属性(在同一类的所有对象之间共享)和方法。 在C中没有类,所以这个function是不相关的。

还有一个用途没有在这里介绍,这是数组types声明的一部分,作为函数的一个参数:

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

在此上下文中,它指定传递给此函数的参数必须是chartypes的数组,其中至less有10个元素。 欲了解更多信息,请看我的问题。

简短的答案… 这取决于。

  1. 静态定义的本地variables不会在函数调用之间失去它们的值。 换句话说,它们是全局variables,但是它们被定义在局部函数中。

  2. 静态全局variables在定义的C文件之外是不可见的。

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

多文件variables作用域示例

ac

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

汇编

 gcc -c ac -o ao gcc -c main.c -o main.o gcc -o main main.o ao 

输出

 m() i = 1 si = 1 m() i = 2 si = 2 a() i = 3 si = 1 a() i = 4 si = 2 

解释

  • si有两个单独的variables,每个文件一个variables
  • 我有一个共享variables

像往常一样,范围越小越好,所以如果可以的话,总是声明variables是static

在C编程中,文件通常用来表示“类”, staticvariables表示类的“私有”成员。

什么标准说这个

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

6.2.2 / 3“标识符的链接”表示static意味着internal linkage

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

和6.2.2 / 2表示internal linkage行为就像我们的例子一样:

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

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

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部分的偏移量,所以我们期望它有所不同。

http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html上的ELF规范中logging了;STB_LOCAL

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

这使其成为代表static的完美select。

没有静态的variables是STB_GLOBAL ,规范说:

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

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

如果我们使用-O3来优化,那么si符号将从符号表中完全移除:反正它不能从外部使用。 为什么没有优化时为什么要在符号表上保留静态variables? 他们可以用于任何事情吗? 也许是为了debugging。

也可以看看

  • 类似于staticfunction: https : //stackoverflow.com/a/30319812/895245
  • 比较staticextern ,这是“相反”: 如何使用extern共享源文件之间的variables?

亲自尝试一下

github上的例子让你玩。

这取决于:

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

该函数将返回1,2,3等 – 该variables不在堆栈上。

AC:

 static int foo() { } 

这意味着这个函数只在这个文件中有作用域。 所以ac和bc可以有不同的foo() ,foo不会暴露给共享对象。 所以如果你在ac中定义了foo,你不能从bc或其他地方访问它。

在大多数C库中,所有“私有”function都是静态的,大部分“公共”function都不是。

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

  • 对项目应用“静态”会强制该项目具有两个属性:(a)在当前范围外不可见; (b)坚持不懈。

它似乎有两个含义的原因是,在C中,可以应用“静态”的每个项目已经具有这两个属性中的一个 ,所以看起来好像该特定用途仅涉及另一个属性

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

对函数应用“静态”就像将其应用于全局variables – 代码必须是持久的(至less在语言中),所以只有可见性才能被改变。

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

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

  1. 你可以在C函数中声明一个静态variables。 这个variables只在函数中可见,但它的行为像一个全局的,它只是初始化一次,它保留了它的值。 在这个例子中,每次调用foo() ,都会打印一个越来越多的数字。 静态variables只被初始化一次。

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

     static void foo() { ... } 

维基百科:

在C编程语言中, static与全局variables和函数一起使用来将它们的作用域设置为包含文件。 在局部variables中,static用于将variables存储在静态分配的内存中,而不是自动分配的内存。 尽pipe语言并不指定任何一种types的内存的实现,但是静态分配的内存通常在编译时被保留在程序的数据段中,而自动分配的内存通常被实现为临时调用栈。

在C中,静态有两个含义,取决于它的使用范围。 在全局范围内,当在文件级声明对象时,意味着该对象只在该文件中可见。

在任何其他范围内,它声明一个对象,该对象将在input特定范围的不同时间之间保持其值。 例如,如果一个int在一个过程中被剥离:

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

在第一次调用过程时,'i'的值被初始化为零,并且在随后调用该过程时保留该值。 如果“我”被打印,它会输出一个0,1,2,3 …的序列

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

总之,静态这个词有两个含义:

  1. Static是两个存储类之一(另一个是自动的)。 静态对象在调用之间保持其值。 在所有块外声明的对象始终是静态的,不能自动生成。
  2. 但是,如果在声明中使用static 关键字 (强调在代码中使用它作为关键字),则会为该对象提供内部链接,因此它只能在该翻译单元中使用。 但是,如果在函数中使用关键字,它将更改对象的存储类(只有在该函数内才能看到该对象)。 静态的反义词是extern关键字,它给出了一个对象的外部链接。

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

  • 在函数内部,保留它在调用之间的值。
  • 在function级别,只有在这个文件中可见。

如果在静态函数中声明一个variables,则其值不会被存储在函数调用堆栈中,并且在再次调用该函数时仍然可用。

如果你声明一个全局variablesstatic,它的作用域将被限制在你声明它的文件中。 这比在整个程序中可以读取和修改的普通全局稍微安全一些。

如果你在mytest.c文件中声明这个:

 static int my_variable; 

那么这个variables只能从这个文件中看到。 该variables不能被导出到其他地方。

如果在函数内部声明,每次调用该函数时,该variables的值将保持其值。

静态函数不能从文件外部导出。 所以在一个* .c文件中,如果你声明它们是静态的,你就隐藏了函数和variables。

需要注意的是,函数中的静态variables在第一次进入该函数时被初始化,并且在调用完成之后仍然保留; 在recursion函数的情况下,静态variables只被初始化一次,并且在所有的recursion调用中,甚至在函数调用完成之后,都一直存在。

如果variables是在函数之外创build的,则意味着程序员只能在variables声明的源文件中使用该variables。

还要注意static可以用4种不同的方式使用。

 to create permanent storage for local variables in a function. to specify internal linkage. to declare member functions that act like non-member functions. to create a single copy of a data member. 

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

 void func(){ static int count; // If you don't declare its value, the value automatically initializes to zero printf("%d, ", count); count++; } void main(){ while(true){ func(); } } 

输出:

0,1,2,3,4,5,…

静态variables值在不同的函数调用之间持续存在,并且作用域仅限于本地块静态variables始终使用值0初始化

C中的静态variables具有程序的生命周期。

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

例如:

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

在上面的程序中, var被存储在数据段中。 它的一生就是整个C程序。

函数调用1之后, var变成2.函数调用2之后, var变成3。

函数调用之间不会破坏var的值。

如果var在非静态variables和局部variables之间存在,它将被存储在C程序中的堆栈段中。 由于该函数的栈框架在函数返回后被销毁, var的值也被破坏。

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

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

试试这个:

在file1.c

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

file2.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的文件范围,链接器将无法parsing对file2.c中使用的variablesx的引用。

参考文献:

  1. http://en.wikipedia.org/wiki/Translation_unit_(programming);
  2. http://en.wikipedia.org/wiki/Call_stack