在C中使用静态函数和变量的原因

在C中使用静态函数和变量的原因,c,static,linker,extern,C,Static,Linker,Extern,我想知道在C语言中如何使用static关键字作为文件中变量的范围限制 在我看来,构建C程序的标准方法是: 有一堆定义函数和变量的c文件,可能范围受限于static 有一堆h文件,声明相应c文件的函数和可能的变量,供其他c文件使用。私有函数和变量不会发布在h文件中 每个c文件都单独编译成一个o文件 所有o文件都链接到一个应用程序文件 如果变量没有在h文件中发布,我认为将gobal声明为static,有两个原因: 一是可读性。告诉未来的读者,包括我自己,在任何其他文件中都不会访问变量 第二个是

我想知道在C语言中如何使用
static
关键字作为文件中变量的范围限制

在我看来,构建C程序的标准方法是:

  • 有一堆定义函数和变量的c文件,可能范围受限于
    static
  • 有一堆h文件,声明相应c文件的函数和可能的变量,供其他c文件使用。私有函数和变量不会发布在h文件中
  • 每个c文件都单独编译成一个o文件
  • 所有o文件都链接到一个应用程序文件
如果变量没有在h文件中发布,我认为将gobal声明为
static
,有两个原因:

  • 一是可读性。告诉未来的读者,包括我自己,在任何其他文件中都不会访问变量
  • 第二个是防止另一个c文件将变量重新声明为
    extern
    。我假设链接器不喜欢既为
    extern
    又为
    static
    的变量。(我不喜欢文件将其他人拥有的变量重新声明为
    extern
    ,这样可以吗?)
还有其他原因吗

静态
函数也是如此。如果原型未发布在h文件中,其他文件可能不会使用该函数,那么为什么要定义它
static

我可以看到同样的两个原因,但没有更多。

通过在文件级别声明变量
static
static
在函数中有不同的含义),您禁止其他单元访问它,例如,如果您试图在另一个单元内使用变量(用
extern
声明),链接器找不到此符号。

如果全局变量声明为静态变量,编译器有时会比未声明时进行更好的优化。因为编译器知道无法从其他源文件访问变量,所以它可以更好地推断代码正在执行的操作(例如“此函数不修改此变量”),这有时会导致它生成更快的代码。很少有编译器/链接器可以在不同的翻译单元上进行这些优化。

< P>当你谈到通知其他读者时,把编译器本身看作读者。如果一个变量被声明为static,这可能会影响优化的程度

静态
变量重新定义为
extern
是不可能的,但编译器会(像往常一样)给您足够的约束,让您上吊

如果我写
静态int-foo
intfoo
在另一种情况下,它们被视为不同的变量,尽管它们具有相同的名称和类型-编译器不会抱怨,但您可能会在以后尝试读取和/或调试代码时感到非常困惑。(如果我在第二种情况下编写
extern int foo;
,除非我在其他地方声明一个非静态
int foo;
,否则链接将失败。)


全局变量很少出现在头文件中,但当它们出现时,应该声明为
extern
。否则,根据编译器的不同,您可能会面临每个包含该头文件的源文件都会声明其自己的变量副本的风险:充其量这将导致链接失败(多定义符号),最坏的情况下会导致几个混淆的暗显情况。

当您声明一个静态函数时,对该函数的调用是一个“近距离呼叫”,理论上它比“远距离呼叫”性能更好“。你可以在谷歌上搜索更多信息。这是我通过简单的谷歌搜索发现的。

我最喜欢的静态用法是能够存储我不必注入或创建要使用的对象的方法,在我看来,私有静态方法总是有用的,在公共场所,你必须花更多的时间来思考你在做什么,以避免crazyscot所定义的那样,让你自己太多的绳索和不小心吊死自己


我喜欢为我的大多数项目的助手类保留一个文件夹,这些项目主要由静态方法组成,可以快速高效地执行任务,不需要对象

如果在文件a.c中声明变量foo而不使其成为静态,在文件b.c中声明变量foo而不使其成为静态,则两者都将自动外部化,这意味着如果初始化两者,链接器可能会抱怨,如果没有抱怨,则分配相同的内存位置。期待调试代码的乐趣


如果在文件a.c中编写函数foo()而不使其成为静态,在文件b.c中编写函数foo()而不使其成为静态,链接器可能会抱怨,但如果没有,对foo()的所有调用都将调用相同的函数。期待调试代码的乐趣

这正是我提到的两个原因之一:“第二个原因是通过将另一个c文件重新定义为
extern
,来防止另一个c文件使用似乎范围有限的全局文件”,我想知道这种做法的质量如何?@Gaunthier所以你的帖子有内部冲突,thenIMO,
static
在所有三种众所周知的用途(文件变量、函数变量、函数)中具有相同的含义,即:“这具有有限的范围,并且在整个程序执行过程中具有恒定的地址”。从这个意义上讲,含义是相同的,但用途不同-
static
在文件级控制可见性,函数级的
static
控制持久性。如果在一个编译单元中声明某个静态对象,则不能在另一个编译单元中将其重新声明为extern。它们将被视为不同的东西。静态还可以防止名称空间污染-例如,您可以有两个编译单元包含一个名为
sort
的函数,它们将被视为不同的东西。有趣的是。我知道这个“extern global in header file”仍然需要在c文件中定义,因为extern在h文件中