【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
我已经在C代码的不同地方看到了static
一词。 这就像C#中的静态函数/类(实现在对象之间共享)吗?
#1楼
多文件变量作用域示例
在这里,我说明了静态如何影响多个文件中函数定义的范围。
交流电
#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“标识符的链接”表示static
表示internal linkage
:
如果对象或函数的文件作用域标识符的声明包含静态的存储类说明符,则该标识符具有内部链接。
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
的理想选择。
没有静态的变量是STB_GLOBAL
,规范说:
当链接编辑器组合了几个可重定位的目标文件时,它不允许名称相同的STB_GLOBAL符号的多个定义。
这与多个非静态定义上的链接错误一致。
如果使用-O3
启动优化,则si
符号将从符号表中完全删除:无论如何不能从外部使用它。 TODO为什么在没有优化的情况下将静态变量完全保留在符号表上? 它们可以用于任何用途吗? 也许用于调试。
也可以看看
- 类似于
static
函数: https : //stackoverflow.com/a/30319812/895245 - 比较
static
与extern
,这与“相反”: 我如何使用extern在源文件之间共享变量?
C ++匿名名称空间
在C ++中,您可能希望使用匿名名称空间而不是静态名称空间,这可以达到类似的效果,但是会进一步隐藏类型定义: 未命名/匿名名称空间与静态函数
#2楼
这里没有涉及另一种用途,它是数组类型声明的一部分,用作函数的参数:
int someFunction(char arg[static 10])
{
...
}
在这种情况下,这指定传递给此函数的参数必须是char
类型的数组,且其中至少包含10个元素。 有关更多信息,请在此处查看我的问题。
#3楼
静态变量值在不同的函数调用之间持续存在,并且其作用域仅限于本地块,而静态var始终以值0初始化
#4楼
重要的是要注意,函数中的静态变量在该函数的第一个条目处被初始化,并且即使在它们的调用完成之后也仍然存在。 在使用递归函数的情况下,静态变量仅初始化一次,并且在所有递归调用中甚至在函数调用完成之后都将持续存在。
如果变量是在函数外部创建的,则意味着程序员只能在已声明该变量的源文件中使用该变量。
#5楼
静态变量是可以在函数中使用的特殊变量,它可以保存两次调用之间的数据,而不会在两次调用之间删除数据。 例如:
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,...
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3142347