C中“static”是什么意思?
我已经看到了在C代码中用于不同地方的static
词。 这就像在C#中的静态函数/类(其中的实现共享对象)?
- 函数内部的静态variables在调用之间保持其值。
- 一个静态的全局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]) { ... }
在此上下文中,它指定传递给此函数的参数必须是char
types的数组,其中至less有10个元素。 欲了解更多信息,请看我的问题。
简短的答案… 这取决于。
-
静态定义的本地variables不会在函数调用之间失去它们的值。 换句话说,它们是全局variables,但是它们被定义在局部函数中。
-
静态全局variables在定义的C文件之外是不可见的。
-
静态函数在定义的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编程中,文件通常用来表示“类”, static
variables表示类的“私有”成员。
什么标准说这个
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。
也可以看看
- 类似于
static
function: https : //stackoverflow.com/a/30319812/895245 - 比较
static
与extern
,这是“相反”: 如何使用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
在不同的环境中意味着不同的东西。
-
你可以在C函数中声明一个静态variables。 这个variables只在函数中可见,但它的行为像一个全局的,它只是初始化一次,它保留了它的值。 在这个例子中,每次调用
foo()
,都会打印一个越来越多的数字。 静态variables只被初始化一次。void foo () { static int i = 0; printf("%d", i); i++ }
-
静态的另一个用途是在.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节中解释它。
总之,静态这个词有两个含义:
- Static是两个存储类之一(另一个是自动的)。 静态对象在调用之间保持其值。 在所有块外声明的对象始终是静态的,不能自动生成。
- 但是,如果在声明中使用
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的引用。
参考文献: