问题是关于普通的c函数,而不是c++ static
方法,正如评论中所阐明的那样 .
好的,我明白 static
变量是什么,但是什么是 static
函数?
为什么如果我声明一个函数,让我们说 void print_matrix
,让我们说 a.c
(没有 a.h
)并包含 "a.c"
- 我得到 "print_matrix@@....) already defined in a.obj"
,但是如果我把它声明为 static void print_matrix
那么它编译?
UPDATE 只是为了清理 - 我知道包括 .c
在内的很糟糕,正如你们许多人指出的那样 . 我只是暂时清除_462214中的空格,直到我更好地了解如何将所有这些功能分组到正确的 .h
和 .c
文件中 . 只是一个临时的快速解决方案 .
10 回答
static
函数是仅对同一文件中的其他函数可见的函数(更准确地说是相同的translation unit) .EDIT :对于那些认为,问题的作者意味着'class method':因为问题标记为
C
,他的意思是一个普通的旧C函数 . 对于(C / Java / ...)类方法,static
表示可以在类本身上调用此方法,不需要该类的实例 .Minimal runnable multi-file scope example
这里我将说明
static
如何影响多个文件中的函数定义范围 .a.c
main.c
Compile
Output
Interpretation
有两个单独的函数
sf
,每个文件一个有一个共享函数
f
像往常一样,范围越小越好,所以如果可以,总是声明函数
static
.在C编程中,文件通常用于表示"classes",而
static
函数表示类的"private"方法 .一个常见的C模式是将
this
结构作为第一个"method"参数传递,这基本上是C在引擎盖下的作用 .What standards say about it
C99 N1256 draft 6.7.1 "Storage-class specifiers"说
static
是"storage-class specifier" .6.2.2 / 3 "Linkages of identifiers"说
static
暗示internal linkage
:和6.2.2 / 2说
internal linkage
在我们的例子中表现得像:其中“翻译单元”是预处理后的源文件 .
How GCC implements it for ELF (Linux)?
随着
STB_LOCAL
绑定 .如果我们编译:
并用以下符号反汇编符号表:
输出包含:
所以绑定是它们之间唯一的重要区别 .
Value
只是它们偏移到.bss
部分,因此我们预计它会有所不同 .STB_LOCAL
记录在http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html的ELF规范中:这使它成为代表
static
的完美选择 .没有静态的函数是
STB_GLOBAL
,规范说:这与多个非静态定义上的链接错误一致 .
如果我们使用
-O3
进行优化,则sf
符号将完全从符号表中删除:无论如何都无法从外部使用它 . TODO为什么在没有优化时根据符号表保留静态函数?他们可以用于任何事情吗?See also
变量相同:https://stackoverflow.com/a/14339047/895245
extern
与static
相反,默认情况下函数已经是extern
:How do I use extern to share variables between source files?Try it yourself
Example on GitHub供你玩 .
以下是关于普通C函数 - 在C类中,修饰符'static'具有另一种含义 .
如果你只有一个文件,这个修饰符绝对没有区别 . 不同之处在于包含多个文件的更大项目:
在C中,每个“模块”(sample.c和sample.h的组合)都是独立编译的,然后每个编译的目标文件(sample.o)由链接器链接到一个可执行文件 .
假设您有几个文件包含在主文件中,其中两个文件只有一个内部用于方便的函数
add(int a, b)
- 编译器可以轻松地为这两个模块创建目标文件,但链接器会抛出错误,因为它找到两个具有相同名称的函数,并且它不知道它应该使用哪个函数(即使在其他地方使用了's nothing to link, because they aren'但在它自己的文件中) .这就是为什么你使这个函数,它只用于内部,一个静态函数 . 在这种情况下编译器不为链接器创建典型的“你可以链接这个东西”-flag,这样链接器就不会看到这个函数,也不会产生错误 .
第一:在另一个文件中包含一个
.cpp
文件通常是一个坏主意 - 它会导致这样的问题:-)通常的方法是创建单独的编译单元,并为包含的文件添加头文件 .其次:
C在这里有一些令人困惑的术语 - 直到评论中指出我才知道它 .
a)
static functions
- 继承自C,你在这里谈论的是什么 . 任何课外 . 静态 function 表示它在当前编译单元外部不可见 - 因此在您的情况下,a.obj具有副本,而您的其他代码具有独立副本 . (使用代码的多个副本来膨胀最终的可执行文件) .b)static member function - 对象方向的术语是静态 method . 住在课堂里 . 您可以使用类而不是通过对象实例来调用它 .
这两种不同的静态函数定义完全不同 . 小心 - 这里是龙 .
Minor nit:静态函数对于翻译单元是可见的,对于大多数实际情况,该函数是定义函数的文件 . 您获得的错误通常被称为违反单一定义规则 .
标准可能会说:
这是查看静态函数的C方式 . 但是,这在C中已弃用 .
另外,在C中,您可以将成员函数声明为static . 这些主要是元函数,即它们不描述/修改特定对象的行为/状态,而是作用于整个类本身 . 此外,这意味着您不需要创建一个对象来调用静态成员函数 . 此外,这也意味着,您只能从这样的函数中访问静态成员变量 .
我将Parrot的例子添加到Singleton模式中,该模式基于这种静态成员函数来在程序的整个生命周期中获取/使用单个对象 .
静态函数的答案取决于语言:
1)在没有像C这样的OOPS的语言中,这意味着该函数只能在其定义的文件中访问 .
2)在像C这样的OOPS语言中,这意味着可以直接在类上调用该函数而无需创建它的实例 .
C中的静态函数与C中的静态成员函数之间存在很大差异 . 在C中,静态函数在其转换单元之外是不可见的,它是编译成的目标文件 . 换句话说,使函数静态限制其范围 . 您可以将静态函数视为其* .c文件的“私有”(尽管这不是严格正确的) .
在C中,“static”也可以应用于类的成员函数和数据成员 . 静态数据成员也称为“类变量”,而非静态数据成员是“实例变量” . 这是Smalltalk术语 . 这意味着类的所有对象只共享一个静态数据成员的副本,而每个对象都有自己的非静态数据成员副本 . 因此,静态数据成员本质上是一个全局变量,它是一个类的成员 .
非静态成员函数可以访问类的所有数据成员:静态和非静态 . 静态成员函数只能对静态数据成员进行操作 .
考虑这一点的一种方法是在C静态数据成员和静态成员函数不属于任何对象,而是属于整个类 .
关于C中的函数,关键字static有两种用途 .
第一种是将函数标记为具有内部链接,因此不能在其他翻译单元中引用它 . 此用法在C中已弃用 . 对于此用法,首选未命名的命名空间 .
第二种用法是在类的上下文中 . 如果一个类具有静态成员函数,则意味着该函数是该类的成员(并且具有对其他成员的通常访问权限),但不需要通过特定对象调用它 . 换句话说,在该函数内部,没有“this”指针 .
静态函数定义将此符号标记为内部 . 因此,从外部链接不可见,但只能看到同一编译单元中的函数,通常是同一个文件 .
静态函数是可以在类本身上调用的函数,而不是类的实例 .
例如,非静态将是:
此方法适用于类的实例,而不是类本身 . 但是,您可以使用静态方法,无需实例即可工作 . 有时在工厂模式中使用: