【问题标题】:When to use static keyword before global variables?何时在全局变量前使用 static 关键字?
【发布时间】:2010-12-23 19:37:43
【问题描述】:

有人能解释一下什么时候应该在头文件中定义的全局变量或常量之前使用 static 关键字吗?

例如,假设我有一个带有以下行的头文件:

const float kGameSpriteWidth = 12.0f;

这是否应该在const 前面有static?使用static 有哪些最佳实践?

【问题讨论】:

  • 请注意,在 C++ 中,static 对于所有全局命名空间 const 限定的变量都是隐含的(即默认为 static),尽管我建议将其限定为 static 无论如何这个意图很明确。
  • 另见How do I use extern to share variables between source files? 那里的答案解释了如何共享值——其中一个关键部分是使用标题来声明(但定义)共享的变量.如果您没有将声明放入的标题,则变量定义应该是静态的。如果您确实有它的标头,请在定义变量的位置(仅是一个源文件)和使用它的位置(可能是许多源文件)都包含标头。

标签: c static keyword


【解决方案1】:

您不应该在头文件中定义全局变量。 您应该在 .c 源文件中定义它们。

  • 如果全局变量仅在一个 .c 文件中可见,则应将其声明为静态。

  • 如果要跨多个 .c 文件使用全局变量,则不应将其声明为静态。 相反,您应该在需要它的所有 .c 文件包含的头文件中声明它。

例子:

  • example.h

    extern int global_foo;
    
  • foo.c

    #include "example.h"
    
    int global_foo = 0;
    static int local_foo = 0;
    
    int foo_function()
    {
       /* sees: global_foo and local_foo
          cannot see: local_bar  */
       return 0;
    }
    
  • bar.c

    #include "example.h"
    
    static int local_bar = 0;
    static int local_foo = 0;
    
    int bar_function()
    {
        /* sees: global_foo, local_bar */
        /* sees also local_foo, but it's not the same local_foo as in foo.c
           it's another variable which happen to have the same name.
           this function cannot access local_foo defined in foo.c
        */
        return 0;
    }
    

【讨论】:

  • 我认为你没有抓住重点。这是一个 const float,在头文件中定义它 static const 并在每个翻译单元中拥有它的不同副本并没有错。但大多数人只会对文字使用#define。
  • 问题是:“有人能解释一下什么时候应该在头文件中定义的全局变量或常量之前使用 static 关键字吗?”由于 OP 似乎是初学者,我只是简单地给出了关于在 C 中定义全局变量的最基本规则。正如您自己注意到的那样——您通常不会在头文件中使用 global _const_s 伤害自己(在 C 中,在 C++ 中并不那么简单)。
  • 毕竟,这只是编译器的强制执行。毕竟,这不过是人的意志……
  • 是否需要在 foo.c 中包含 example.h?
  • @hammadian 在这种情况下没有必要。仍然包含它是一个好主意。它使编译器有机会检测 h 文件中的声明和 c 文件中的定义之间的任何差异。
【解决方案2】:

static 将变量呈现为文件的本地变量,这通常是一件好事,例如参见 this Wikipedia entry

【讨论】:

  • 我认为这与“文件”无关,而是与“编译模块”有关。
  • 如果变量不是extern,则无法从C 文件外部访问它。那么将其定义为静态的意义何在?
  • @alex 一个很好的问题。默认情况下,全局变量是外部变量,但无论如何最好将其标记为外部变量。
  • @Arak 准确地说,它与“编译单元”有关——我相信这是正确的命名。我知道这个问题没有 C++ 标记,但实际的编译模块符合新的 C++ 标准,所以最好不要混淆。
【解决方案3】:

是的,使用静态

除非您需要从不同的.c 模块引用对象,否则请始终在.c 文件中使用静态。

永远不要在.h 文件中使用静态,因为每次包含它都会创建一个不同的对象。

【讨论】:

  • 链接器看不到它们是常量并优化掉所有不同的对象?
  • 但它们不是常量,重要的是链接器不会仅仅因为私有对象具有相同的名称而意外地将它们合并在一起。链接器根本没有高级信息,它们只处理符号、位串、空间和引用。常量对链接器根本不可见,它们只会在编译期间影响生成的代码。
  • 另一种说法是:static 的全部意义在于允许同名是两个不同模块中的两个不同对象。
【解决方案4】:

头文件的经验法则:

  • 将变量声明为extern int foo;,并将相应的初始化放在单个源文件中,以获得跨翻译单元共享的可修改值
  • 使用static const int foo = 42; 获取可以内联的常量

【讨论】:

    【解决方案5】:

    static 关键字在 C 中用于限制函数或变量对其翻译单元的可见性。翻译单元是生成目标文件的 C 编译器的最终输入。

    检查这个:Linkage | Translation unit

    【讨论】:

      【解决方案6】:

      static 在全局变量之前意味着无法从定义它的编译模块外部访问该变量。

      例如假设您想访问另一个模块中的变量:

      foo.c
      
      int var; // a global variable that can be accessed from another module
      // static int var; means that var is local to the module only.
      ...
      
      bar.c
      
      extern int var; // use the variable in foo.c
      ...
      

      现在,如果您将 var 声明为静态,则除了 foo.c 编译到的模块之外,您无法从任何地方访问它。

      注意,一个模块是当前源文件,加上所有包含的文件。也就是说,您必须单独编译这些文件,然后将它们链接在一起。

      【讨论】:

        【解决方案7】:

        匿名命名空间中 C++ 的正确机制。如果你想要文件本地的东西,你应该使用匿名命名空间而不是静态修饰符。

        【讨论】:

        • 我认为这个答案措辞不好,过于简洁和离题(虽然 OP 没有具体说明,但问题被标记为 C,而不是 C++)。
        【解决方案8】:

        全局静态变量在编译时初始化,不像自动

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-24
          相关资源
          最近更新 更多