我已经static
在C代码的不同地方看到过这个词;这就像C#中的静态函数/类(实现在对象之间共享)吗?
我已经static
在C代码的不同地方看到过这个词;这就像C#中的静态函数/类(实现在对象之间共享)吗?
Answers:
如果您是新手,则(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与全局变量和函数一起使用以将其范围设置为包含文件。在局部变量中,static用于将变量存储在静态分配的内存中,而不是自动分配的内存中。虽然该语言没有规定哪种类型的内存的实现,但是静态分配的内存通常在编译时保留在程序的数据段中,而自动分配的内存通常实现为瞬时调用堆栈。
要回答您的第二个问题,它与C#中的情况不同。
但是,在C ++中,static
它也用于定义类属性(在同一类的所有对象之间共享)和方法。在C中没有类,因此此功能无关紧要。
.c
头文件堆,但是魔鬼总是处在不典型的地方。
这里没有涉及另一种用途,它是数组类型声明的一部分,用作函数的参数:
int someFunction(char arg[static 10])
{
...
}
在这种情况下,这指定传递给此函数的参数必须是类型数组,char
其中至少包含10个元素。有关更多信息,请在此处查看我的问题。
arg[0]
通过arg[9]
它具有值(这也意味着该函数不接受空指针)。编译器可以以某种方式利用此信息进行优化,而静态分析器可以利用该信息来确保函数永远不会被赋予空指针(或者,如果可以告诉它,则其数组比指定的元素要少)。
static
C99中赋予的新的重载含义。它已经存在了十五年半了,但是并不是所有的编译器作者都接受了C99的所有功能-因此,整个C99在很大程度上仍然是未知的。
int arr[n];
是V99(可变长度数组),它是在C99中添加的。这是你的意思吗?
简短的回答... 这取决于。
静态定义的局部变量在函数调用之间不会丢失其值。换句话说,它们是全局变量,但范围仅限于定义它们的局部函数。
静态全局变量在定义它们的C文件之外不可见。
静态函数在定义它们的C文件之外不可见。
private
C语言中没有,但您的类比很好:静态使事物“私有”到给定文件。C中的文件通常映射到C ++中的类。
多文件变量作用域示例
在这里,我说明了静态如何影响多个文件中函数定义的范围。
交流电
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/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 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
在http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html的ELF规范中有记录:
STB_LOCAL本地符号在包含其定义的目标文件之外不可见。多个文件中可能存在相同名称的本地符号,而不会互相干扰
这使其成为代表的完美选择static
。
没有static的变量是STB_GLOBAL
,规范说:
当链接编辑器组合了几个可重定位的目标文件时,它不允许名称相同的STB_GLOBAL符号的多个定义。
这与多个非静态定义上的链接错误一致。
如果使用来启动优化-O3
,则si
符号将从符号表中完全删除:无论如何都不能从外部使用它。TODO为什么在没有优化的情况下将静态变量完全保留在符号表上?它们可以用于任何用途吗?也许用于调试。
也可以看看
static
功能:https : //stackoverflow.com/a/30319812/895245static
有extern
,这不“相反”:如何使用的extern源文件之间共享变量?C ++匿名名称空间
在C ++中,您可能希望使用匿名名称空间而不是静态名称空间,这可以达到类似的效果,但是会进一步隐藏类型定义:未命名/匿名名称空间与静态函数
这取决于:
int foo()
{
static int x;
return ++x;
}
该函数将返回1、2、3等。---变量不在堆栈中。
static int foo()
{
}
这意味着此功能仅在此文件中具有作用域。因此ac和bc可以具有不同的foo()
s,而foo不暴露给共享对象。因此,如果您在ac中定义了foo,则无法b.c
从任何其他位置访问它。
在大多数C库中,所有“私有”功能都是静态的,而大多数“公共”功能不是静态的。
人们一直说C语言中的“静态”有两个含义。我提供了另一种查看方式,使它具有单一含义:
它似乎有两个含义的原因是,在C语言中,可能对其应用“静态”的每个项目都已经具有这两个属性之一,因此似乎该特定用法仅涉及另一个。
例如,考虑变量。在函数外部声明的变量已经具有持久性(在数据段中),因此应用“静态”只能使它们在当前作用域(编译单元)之外不可见。相反,在函数内部声明的变量在当前作用域(函数)之外已经不可见,因此应用“静态”只能使它们持久化。
将“静态”应用于函数就像将其应用于全局变量一样-代码必须是持久的(至少在语言中),因此只能更改可见性。
注意:这些注释仅适用于C。在C ++中,将'static'应用于类方法确实为关键字赋予了不同的含义。对于C99数组参数扩展类似。
static
给标识符提供内部链接。
从维基百科:
在C编程语言中,static与全局变量和函数一起使用以将其范围设置为包含文件。在局部变量中,static用于将变量存储在静态分配的内存中,而不是自动分配的内存中。虽然该语言没有规定哪种类型的内存的实现,但是静态分配的内存通常在编译时保留在程序的数据段中,而自动分配的内存通常实现为瞬时调用堆栈。
我讨厌回答一个老问题,但是我认为没有人在“ C编程语言”的A4.1节中提到过K&R如何解释它。
简而言之,“静态”一词具有两种含义:
static
关键字(将重点放在代码中作为关键字使用时)与声明一起使用时,它将为对象提供内部链接,因此只能在该翻译单元中使用。但是,如果在函数中使用关键字,则它将更改对象的存储类(无论如何,该对象仅在该函数中可见)。与static相反的是extern
关键字,它为对象提供外部链接。Peter Van Der Linden在“专家C编程”中给出了这两种含义:
register
了存储类说明符(C99 6.7.1存储类说明符)。这不仅仅是提示,例如,无论编译器是否分配寄存器,您都不能&
在存储类对象上应用地址运算符register
。
C语言中的静态变量具有程序的生命周期。
如果在函数中定义,则它们具有局部作用域,即只能在这些函数内部访问它们。静态变量的值在函数调用之间保留。
例如:
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
在非静态变量和局部变量之间,则将其存储在C程序的堆栈段中。由于函数返回后会破坏函数的堆栈框架,因此的值var
也会被破坏。
初始化的静态变量存储在C程序的数据段中,而未初始化的静态变量存储在BSS段中。
有关静态的另一信息:如果变量是全局和静态的,则它具有C程序的生命周期,但具有文件作用域。它仅在该文件中可见。
尝试一下:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
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的引用,这将导致链接器错误。
参考文献:
static int var = 1;
值改回一个值
静态变量是可以在函数中使用的特殊变量,它可以保存两次调用之间的数据,而不会在两次调用之间删除数据。例如:
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,...
printf("%d, ", count); count++;
用`printf(“%d,”,count ++)代替(没关系:P)。
静态变量即使在超出范围后也具有保留其值的属性!因此,静态变量将其先前值保留在其先前范围中,并且不会在新范围中再次初始化。
例如看一下-程序运行时,静态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]
这些是我发现的主要功能,上面没有为新手解释!
在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变量。