【问题标题】:Reasons to use Static functions and variables in C在 C 中使用静态函数和变量的原因
【发布时间】:2011-02-27 18:23:58
【问题描述】:

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

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

  • 有一堆定义函数和变量的 c 文件,可能范围受限于 static
  • 有一堆h文件声明了相应c文件的函数和可能的变量,供其他c文件使用。私有函数和变量未在 h 文件中发布。
  • 每个 c 文件都单独编译成一个 o 文件。
  • 所有 o 文件都链接到一个应用程序文件。

如果变量未在 h 文件中发布,我看到将 gobal 声明为 static 的两个原因:

  • 一个是为了可读性。通知未来的读者,包括我自己,任何其他文件都没有访问变量。
  • 二是防止另一个c文件将变量重新声明为extern。我想链接器不喜欢既是extern 又是static 的变量。 (我不喜欢文件将其他人拥有的变量重新声明为extern 的想法,这样可以吗?)

还有其他原因吗?

static 函数也是如此。如果原型没有发布在 h 文件中,其他文件可能无论如何都不会使用该功能,那为什么要定义它static 呢? 我可以看到相同的两个原因,但仅此而已。

【问题讨论】:

  • 六年后,我现在知道static 不限制范围,它提供了内部链接。如果您将翻译单元视为一个范围,则类似,但不是正确的术语。

标签: c static linker extern


【解决方案1】:

当您谈到通知其他读者时,请将编译器本身视为读者。如果一个变量被声明为static,这会影响优化的程度。

static 变量重新定义为extern 是不可能的,但是编译器会(像往常一样)给你足够的绳索让你上吊。

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

全局变量很少出现在头文件中,但当它们出现时,它们应该被声明为extern。如果不是,则取决于您的编译器,您可能会冒每个包含该标头的源文件都将声明其自己的变量副本的风险:最好的情况是这将导致链接失败(多重定义的符号),最坏的情况是会导致一些令人困惑的遮蔽情况。

【讨论】:

  • 有趣。我知道这个“extern global in header file”仍然需要在 c 文件中定义,因为 h 文件中的 extern 使它成为一个简单的声明。
【解决方案2】:

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

【讨论】:

  • 这正是我提到的两个原因之一:“第二个是通过将其重新声明为extern来防止另一个c文件使用看似范围有限的全局。”我想知道这种做法的质量?
  • @Gaunthier 所以你的帖子有内部冲突
  • IMO, static 在所有三个众所周知的用途(文件变量、函数变量、函数)中具有相同的含义,即:“这具有有限的范围,并且在整个程序中都有一个常量地址执行”。
  • 嗯,在这个意义上意义是相同的,但目的不同——static 在文件级别控制可见性,static 在功能级别控制持久性。
  • 如果你在一个编译单元中声明了一些静态的东西,你不能在另一个编译单元中将它重新声明为 extern。它们将被视为不同的事物。 static 还用于防止命名空间污染 - 例如你可以有 2 个编译单元包含一个名为 sort 的函数,它们将被视为不同的东西。
【解决方案3】:

当您声明一个静态函数时,对该函数的调用是“近调用”,理论上它比“远调用”执行得更好。您可以谷歌了解更多信息。 This 是我通过简单的谷歌搜索找到的。

【讨论】:

  • 也很有趣,虽然依赖于平台(我的目标只有一条绝对的 CALL 指令,没有远/近)。
  • 例如gcc 可以在许多平台上为静态函数切换调用约定(更快)。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

    如果你在文件 ac 中编写了一个函数 foo() 而不使其成为静态,并且在文件 bc 中编写一个函数 foo() 而不使其成为静态,链接器可能会抱怨,但如果没有,所有对 foo( ) 将调用相同的函数。期待调试您的代码的乐趣。

    【讨论】:

      【解决方案6】:

      我最喜欢的 static 用法是能够存储我不必注入或创建要使用的对象的方法,在我看来,私有静态方法总是有用的,在 public static 你必须放更多是时候想想你做了什么来避免被疯子定义的东西,让你的自己绳索太多,不小心把自己吊起来!

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

      【讨论】:

      • 问题是关于 C,而不是 C++。在 C 中没有类,没有方法,也没有私有成员。此外,在 C++ 中,静态函数和静态方法是有区别的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多