static
有人告诉我,在一个文件中定义的函数.c
不能从其他文件访问。但在下面的程序中,我可以static void show()
从另一个文件访问该函数。我对static
C 函数的理解是错误的吗?
啊(第一个文件):
static void show()
{
printf("I am in static show function in a.c");
}
bc(另一个文件):
#include"a.h"
void main()
{
show();
}
static
有人告诉我,在一个文件中定义的函数.c
不能从其他文件访问。但在下面的程序中,我可以static void show()
从另一个文件访问该函数。我对static
C 函数的理解是错误的吗?
啊(第一个文件):
static void show()
{
printf("I am in static show function in a.c");
}
bc(另一个文件):
#include"a.h"
void main()
{
show();
}
请记住,这#include
是通过复制和粘贴包含文件的内容来实现的。因此,在您的示例中,#include
处理完之后,您会得到以下信息:
static void show()
{
printf("I am in static show function in a.c");
}
void main()
{
show();
}
如此清晰main
可见show
。1
解决方案是不 #include
使用.c 文件。通常,您应该只使用#include
标头 (.h) 文件。您的静态函数不应在头文件中声明或定义,因此main
将无法看到它。
show
,一个 ina.c
和一个 in b.c
。对于static
函数,这不是问题,但对于非static
函数,您会收到链接器错误。
static
关键字将链接规范更改为内部链接。
标记为的函数static
仅在该Translation Unit(TU)中可见。
也许,您在访问该功能的特定 TU 中有相同的命名符号可用。其中的部分只有在您向我们展示代码后才能回答。
编辑:
当您static
在头文件中定义一个函数时,将在包含它的每个翻译单元中创建相同函数的副本。此类函数的每个实例都被视为一个单独的函数(每个函数的地址不同)并且每个这些函数的实例有自己的static
局部变量和字符串文字的副本。
显然,这将起作用,但这也可能会增加生成的二进制文件的大小。
其他答案是正确的,但说静态函数不能从另一个文件访问并不十分准确。可以通过函数指针访问函数。更准确地说,该函数的名称在另一个翻译单元中是不可访问的。
请记住,将 C 源代码转换为可执行程序包括概念阶段,包括:
#include
指令被包含文件的内容替换假设我们有三个文件。 foo.h
:
typedef void (*void_function_p)(void);
extern void_function_p foo(void);
foo.c
:
#include "foo.h"
#include <stdio.h>
static void baz(void) {
printf("worked!\n");
}
void_function_p foo(void) {
return baz;
}
bar.c
:
#include "foo.h"
#include <stdio.h>
int main(void) {
(*foo())();
return 0;
}
该程序编译并打印“工作!” 当它运行时。
这里有两个翻译单元。一种是预处理中的代码foo.c
(由于其#include
工作原理,它还包括 和 中的代码foo.h
)stdio.h
。另一个是预处理中的代码(同样,它在andbar.c
中有自己的代码副本)。foo.h
stdio.h
通过让函数foo
返回指向静态函数的指针baz
,我们可以baz
从main
函数中调用。
现在,考虑如果我们修改main
为如下所示会发生什么:
int main(void) {
(*foo())();
baz();
return 0;
}
此代码将导致链接器错误,因为baz
此翻译单元中的名称无法链接到baz
其他翻译单元中的定义。
这是静态函数的第一个优点:另一个程序员不会意外地baz
从另一个翻译单元访问我们的函数。
现在,考虑如果我们修改bar.c
为如下所示会发生什么:
#include "foo.h"
#include <stdio.h>
static void baz(void) {
printf("still works!");
}
int main() {
(*foo())();
baz();
return 0;
}
此代码将编译并打印“工作!” 其次是“仍然有效!”
这是静态函数的第二个优点:我们定义了两个同名的函数(在不同的翻译单元中)。
如果您尝试将两个静态定义放在同一个翻译单元中,您将收到关于定义baz
两次的编译器错误。
最后要注意的是,如果您使用现在的程序并删除所有static
s,则会导致链接器错误,因为baz
已经定义了两次(使用外部链接),这是不允许的。