What is a “static” function?
问题是关于C函数,而不是C++ EDCOX1,0种方法,如注释中所阐明的。
好的,我知道
为什么我要声明一个函数,比如说
更新只是为了澄清问题-我知道包括
编辑:对于那些认为问题的作者意味着"类方法"的人:当问题被标记为
C中的静态函数和C++中的静态成员函数之间有很大的区别。在C语言中,静态函数在其翻译单元(即编译到其中的对象文件)之外是不可见的。换句话说,使一个函数成为静态的限制了它的范围。您可以将静态函数视为它的*.c文件的"私有"(尽管这并不完全正确)。
在C++中,"static"也可以应用于类的成员函数和数据成员。静态数据成员也称为"类变量",而非静态数据成员则称为"实例变量"。这是小话术语。这意味着一个类的所有对象只共享一个静态数据成员的副本,而每个对象都有自己的非静态数据成员副本。所以静态数据成员本质上是一个全局变量,它是一个类的成员。
非静态成员函数可以访问类的所有数据成员:静态和非静态。静态成员函数只能对静态数据成员进行操作。
考虑这一点的一个方法是,在C++中,静态数据成员和静态成员函数不属于任何对象,而是属于整个类。
对于C++中的函数,关键字静态有两种用法。
第一种方法是将函数标记为具有内部链接,这样它就不能在其他翻译单元中引用。这种用法在C++中是不适用的。此用法首选未命名的命名空间。
1 2 3 4 5 6 7 8 9 10 11 12 | // inside some .cpp file: static void foo(); // old"C" way of having internal linkage // C++ way: namespace { void this_function_has_internal_linkage() { // ... } } |
第二种用法是在类的上下文中。如果一个类有一个静态成员函数,这意味着该函数是该类的成员(并且通常可以访问其他成员),但不需要通过特定的对象调用它。换句话说,在这个函数内部,没有"this"指针。
最小可运行多文件作用域示例
在这里,我将说明
A.C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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 */ /*void f() { puts("a f"); }*/ /* OK: only declared, not defined. Will use the one in main. */ void f(void); /* OK: only visible to this file. */ static void sf() { puts("a sf"); } void a() { f(); sf(); } |
主C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Github上游。
编译并运行:
1 2 3 4 | gcc -c a.c -o a.o gcc -c main.c -o main.o gcc -o main main.o a.o ./main |
输出:
1 2 3 4 | main f main sf main f a sf |
解释
- 有两个单独的函数
sf ,每个文件一个 - 有一个单一的共享函数
f 。
和往常一样,范围越小越好,所以如果可以的话,总是声明函数
在C语言编程中,文件通常用来表示"类",而
一个常见的C模式是将EDCOX1的5个结构作为第一个"方法"参数传递,这基本上是C++在引擎盖下所做的。
标准怎么说呢
c99 n1256草案6.7.1"存储类说明符"表示
6.2.2/3"标识符链接"表示
If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
6.2.2/2表示,在我们的示例中,
In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function.
其中"翻译单元"是预处理后的源文件。
GCC如何为ELF(Linux)实现它?
与
如果我们编译:
1 2 | int f() { return 0; } static int sf() { return 0; } |
将符号表分解为:
1 | readelf -s main.o |
输出包括:
1 2 3 | Num: Value Size Type Bind Vis Ndx Name 5: 000000000000000b 11 FUNC LOCAL DEFAULT 1 sf 9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f |
所以它们之间的结合是唯一显著的区别。
STB_LOCAL Local symbols are not visible outside the object file containing their definition. Local symbols of the same name may exist in multiple files without interfering with each other
这使得代表
没有静态的函数是
When the link editor combines several relocatable object files, it does not allow multiple definitions of STB_GLOBAL symbols with the same name.
这与多个非静态定义上的链接错误是一致的。
如果我们使用
也见
- 变量相同:https://stackoverflow.com/a/14339047/895245
extern 与static 相反,默认情况下函数已经是extern :如何使用extern在源文件之间共享变量?
C++匿名命名空间
在C++中,您可能希望使用匿名命名空间而不是静态的,这实现了类似的效果,但进一步隐藏了类型定义:未命名/匿名命名空间与静态函数。
型
下面是关于C函数的简单说明——在C++类中,修饰符"static"有另一个含义。
如果只有一个文件,那么这个修改器就没有任何区别。不同之处在于具有多个文件的大型项目:
在C语言中,每个"模块"(sample.c和sample.h的组合)都是独立编译的,然后每个编译的对象文件(sample.o)都被链接器链接到一个可执行文件。
假设您有几个包含在主文件中的文件,其中两个文件的函数只在内部使用,方便称为
这就是为什么您要使这个只在内部使用的函数成为一个静态函数的原因。在这种情况下,编译器不会为链接器创建典型的"你可以链接这个东西"标志,这样链接器就不会看到这个函数,也不会生成错误。
第一:在另一个文件中包含一个
其次:
C++在这里有一些令人困惑的术语,直到我在评论中指出,我才知道。
a)
b)
这两个不同的静态函数定义是完全不同的。小心点-这里是龙。
静态函数定义将此符号标记为内部符号。因此,从外部进行链接时,它将不可见,而只可见于同一编译单元(通常是同一文件)中的函数。
静态函数是可以在类本身上调用的函数,而不是类的实例。
例如,非静态的将是:
1 2 | Person* tom = new Person(); tom->setName("Tom"); |
此方法在类的实例上工作,而不是类本身。但是,您可以有一个静态方法,它可以在没有实例的情况下工作。这有时用于工厂模式:
1 | Person* tom = Person::createNewPerson(); |
静态函数的答案取决于语言:
1)在C等没有OOP的语言中,这意味着函数只能在其定义的文件中访问。
2)在像C++这样的OOP语言中,这意味着函数可以直接在类上调用,而不必创建它的实例。
型
次要NIT:静态函数对翻译单元是可见的,在大多数实际情况下,它是函数定义所在的文件。您得到的错误通常被称为违反了一个定义规则。
标准可能会说:
"Every program shall contain exactly one definition of every noninline
function or object that is used in that program; no diagnostic
required."
号
这是查看静态函数的C方法。然而,这在C++中是不受欢迎的。
另外,在C++中,可以声明成员函数为静态函数。这些大多是元函数,即它们不描述/修改特定对象的行为/状态,而是作用于整个类本身。另外,这意味着您不需要创建一个对象来调用静态成员函数。此外,这也意味着,您只能从这样的函数中访问静态成员变量。
我将在Parrot的示例中添加基于此类静态成员函数的单例模式,以在程序的整个生命周期中获取/使用单个对象。