我在C代码的不同地方看到过静态这个词;这是否像c#中的静态函数/类(实现是跨对象共享的)?
当前回答
多文件变量范围示例
在这里,我将说明静态如何跨多个文件影响函数定义的作用域。
a.c
#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("");
}
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只有一个共享变量
通常,作用域越小越好,所以如果可以,总是将变量声明为静态的。
在C语言编程中,文件经常被用来表示“类”,静态变量表示类的私有静态成员。
这是什么标准啊
C99 N1256草案6.7.1“存储类说明符”说static是一个“存储类说明符”。
6.2.2/3“标识符的关联”说静态意味着内部关联:
如果对象或函数的文件作用域标识符声明中包含存储类说明符static,则该标识符具有内部链接。
6.2.2/2表示内部链接的行为就像我们的例子:
在构成整个程序的翻译单元和库的集合中,带有外部链接的特定标识符的每个声明都表示相同的对象或函数。在一个翻译单元中,带有内部链接的标识符的每个声明都表示相同的对象或函数。
其中“翻译单元是预处理后的源文件。
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:上有文档
局部符号在包含其定义的目标文件之外是不可见的。相同名称的局部符号可以存在于多个文件中而互不干扰
这使得它成为代表静态的完美选择。
不带static的变量是STB_GLOBAL,规范说:
当链接编辑器组合了几个可重定位的目标文件时,它不允许使用相同名称定义多个STB_GLOBAL符号。
这与多个非静态定义的链接错误是一致的。
如果我们使用-O3进行优化,si符号将完全从符号表中删除:它无论如何都不能从外部使用。当没有优化时,为什么要在符号表上保持静态变量?它们有什么用途吗?也许用于调试。
另请参阅
类似于静态函数:https://stackoverflow.com/a/30319812/895245 比较static和extern,它做“相反”:我如何使用extern在源文件之间共享变量?
C+匿名namespaces
在c++中,您可能希望使用匿名名称空间而不是静态名称空间,这可以达到类似的效果,但进一步隐藏了类型定义:未命名/匿名名称空间vs.静态函数
其他回答
这里还有一种用法没有涉及,它是数组类型声明的一部分,作为函数的参数:
int someFunction(char arg[static 10])
{
...
}
在这个上下文中,它指定传递给这个函数的参数必须是char类型的数组,其中至少有10个元素。更多信息请看我的问题。
静态在不同的语境中有不同的含义。
你可以在C函数中声明一个静态变量。这个变量只在函数中可见,但它的行为像一个全局变量,因为它只初始化一次,并保留其值。在这个例子中,每次调用foo(),它都会输出一个递增的数字。静态变量只初始化一次。 Void foo () { 静态int I = 0; printf (" % d”,我);我+ + } static的另一种用法是在.c文件中实现一个函数或全局变量,但不希望它的符号在文件生成的.obj之外可见。如。 静态无效foo(){…}
静态变量有一个特性,即使在它们超出作用域后也能保存它们的值!因此,静态变量在以前的作用域中保留它们以前的值,而在新的作用域中不再初始化。
看看这个例子 静态int变量在程序运行时保留在内存中。当声明变量的函数调用结束时,普通变量或自动变量将被销毁。
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
这将输出:12
As 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)
这些是我发现的主要问题,上面没有为新手解释!
如果你在mytest.c文件中声明这个:
static int my_variable;
那么这个变量只能从这个文件中看到。该变量不能导出到其他任何地方。
如果在函数内部声明,则每次调用该函数时,变量的值将保持不变。
静态函数不能从文件外部导出。因此,在*.c文件中,如果将函数和变量声明为静态,则隐藏了它们。
在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 = 0。当我们执行counterFunction时,它会销毁count变量。
推荐文章
- PHP中的三个点(…)是什么意思?
- C多行宏:do/while(0) vs作用域块
- 关键字使用virtual+override vs. new
- time_t最终的类型定义是什么?
- 我需要显式处理负数或零时,总和平方数字?
- 函数名周围的括号是什么意思?
- 用C语言创建自己的头文件
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- 如果私有帮助方法可以是静态的,那么它们应该是静态的吗
- main()中的Return语句vs exit()
- 如果不是内存地址,C指针到底是什么?
- 在numpy数组中提取特定列
- c#二进制字面值
- 我如何在Visual Studio中预处理后看到C/ c++源文件?
- 在Ruby中使用范围填充数组的正确方法