将函数声明为静态和不将其包含在 header 中有什么区别?

What's the difference between declaring a function static and not including it in a header?

以下场景有什么区别?

// some_file.c
#include "some_file.h" // doesn't declare some_func

int some_func(int i) {
    return i * 5;
}
// ...

// some_file.c
#include "some_file.h" // doesn't declare some_func

static int some_func(int i) {
    return i * 5;
}
// ...

如果所有 static 对函数所做的只是限制它们对其文件的访问,那么这两种情况是否都意味着 some_func(int i) 只能从 some_file.c 访问,因为在这两种情况下都不是some_func(int i) 放入 header 文件?

不同之处在于,对于非静态函数,它仍然可以在其他一些翻译单元中声明(头文件与这一点无关)并被调用。从任何其他翻译单元根本看不到静态函数。

甚至在另一个函数中声明一个函数也是合法的:

foo.c:
void foo()
{
  void bar();
  bar();
}

bar.c:
void bar()
{ ... }

静态函数是 "local" 声明它的 .c 文件。所以你可以在另一个 .c 文件中有另一个函数(static 或 nor)而不会发生名称冲突。

如果.c 文件中有一个未在任何头文件中声明的非静态函数,则不能从另一个.c 文件中调用此函数,但也不能在另一个文件中有另一个同名函数.c 文件,因为这会导致名称冲突。

结论:所有纯本地函数(仅在 .c 函数内部使用的函数,例如本地辅助函数)都应声明为静态的,以防止名称污染 space.

正确用法示例:

file1.c

static void LocalHelper()
{
}
...

file2.c

static void LocalHelper()
{
}
...

半正确用法示例

file1.c

static LocalHelper()   // function is local to file1.c
{
}
...

file2.c

void LocalHelper()     // global functio
{
}
...

file3.c

void Foo()
{
   LocalHelper();    // will call LocalHelper from file2.c
}
...

在这种情况下,程序将 link 正确,即使 LocalHelper 在 file2.c

中应该是静态的

错误用法示例

file1.c

LocalHelper()          // global function
{
}
...

file2.c

void LocalHelper()     // global function
{
}
...

file3.c

void Foo()
{
   LocalHelper();       // which LocalHelper should be called?
}
...

在最后一个例子中,我们有一个 nema 碰撞,程序甚至不会 link。

What's the difference between declaring a function static and not including it in a header?

阅读有关 C programming language (e.g. Modern C), the C11 standard n1570. Read also about linkers and loaders 的更多信息。

在 POSIX 系统上,特别是 Linux,阅读 dlopen(3), dlsym(3),等等...

实际来说:

如果你声明一个函数 static 它对其他人保持不可见 translation units (concretely your *.c source files, with the way you compile them: you could -at least in principle, even if it is confusing- compile foo.c twice with GCC on Linux: once as gcc -c -O -DOPTION=1 foo.c -o foo1.o and another time with gcc -c -O -DOPTION=2 -DWITHOUT_MAIN foo.c -o foo2.o and in some cases be able to link both foo1.o and foo2.o object files into a single executable foo 使用 gcc foo1.o foo2.o -o foo)

如果你不声明它static,你可以(即使它很糟糕)在一些其他[=52]中编码=] 翻译单元类似于:

if (x > 2) {
  extern int some_func(int); // extern is here for readability
  return some_func(x);
}

在实践中,我习惯用唯一的名称命名我所有的 C 函数(包括 static 个),并且我通常有一个与之相关的命名约定(例如用一个共同的前缀命名它们,比如 GTK does). This makes debugging the program (with GDB) 更容易(因为 GDB 有自动完成函数名称)。

最后,一个好的 optimizing compiler could, and practically would often, inline calls to static functions whose body is known. With a recent GCC,用 gcc -O2 -Wall 编译你的代码。如果您想检查内联是如何发生的,请查看生成的汇编程序(使用 gcc -O2 -S -fverbose-asm)。

在 Linux 上,您可以使用 dlsym 获取未声明的函数的地址 static