【问题标题】:How do I share variables between different .c files? [duplicate]如何在不同的 .c 文件之间共享变量? [复制]
【发布时间】:2010-11-05 22:34:23
【问题描述】:

关于 C 声明的初学者问题:

在一个.c文件中,如何使用另一个.c文件中定义的变量?

【问题讨论】:

  • 我更改了你的标题。尝试使标题更具描述性,以便 1) 能够回答它的人可以轻松地看到您在问什么,以及 2) 其他有相同问题的人将能够找到这个问题,所以他们不会'不必再问了。在查看问题列表时,我们不需要知道这是一个初学者问题,但我们确实需要知道问题是关于什么的。只是对未来问题的提示。 :)

标签: c


【解决方案1】:

在文件 A.c 中:

int myGlobal = 0;

在文件A.h中

extern int myGlobal;

在文件 B.c 中:

#include "fileA.h"
myGlobal = 1;

这就是它的工作原理:

  • 该变量位于 fileA.c 中
  • fileA.h 告诉全世界它存在,它的类型是什么 (int)
  • fileB.c 包含 fileA.h,以便编译器在 fileB.c 尝试使用之前知道 myGlobal。

【讨论】:

  • 当变量是静态时,它给我一个链接错误,“无法解析的符号”,如何处理?
  • @jfq:非类上下文中的“静态”表示“仅限于此翻译单元”。它本质上与“外部”相反。你不能同时拥有两者。
  • 只是备注——如果变量的所有者是main.c文件,而没有main.h呢?
  • @arbitter:没有头文件,你不能共享变量(除非你把extern int myGlobal;直接放到想要访问myGlobal的源文件中,但这是对DRY的严重违反)。如果你需要从 main.c 共享一个全局,create main.h!
  • @RichieHindle:不确定我是否可以制作一个 main.h,但我将把它放在另一个文件中,谢谢!
【解决方案2】:

在 99.9% 的情况下,在文件之间共享非常量的全局变量是糟糕的程序设计。您真正需要这样做的情况很少:它们非常罕见,以至于我无法提出任何有效的案例。可能是硬件寄存器的声明。

在大多数情况下,您应该使用(可能是内联的)setter/getter 函数(“public”)、文件范围内的静态变量(“private”)或不完整的类型实现(“private”)。

在极少数情况下,当您需要在文件之间共享变量时,请执行以下操作:

// file.h
extern int my_var;

// file.c
#include "file.h"
int my_var = something;

// main.c
#include "file.h"
use(my_var);

切勿将任何形式的变量定义放在 h 文件中。

【讨论】:

  • 我发布了这个作为对这个帖子的完全副本的回答。我觉得一些关于使用全局变量的建议是必要的,而不是在没有首先发出警告的情况下盲目地向他人传授不良做法。
  • 考虑到您夸大了全局变量的有效案例是多么罕见,您的帖子太自以为是了。在我的脑海中,控制嵌入式系统中资源可用性的二进制信号量必须是全局的。任何共享资源的基于 RTOS 的固件都将充斥着全局信号量。同样,当全局代表真正应该随处可用的东西时,它在速度和开发方面都可以更简单、更快。此外,单例基本上是带有一些语法糖的全局变量。过于简单化?是的,但在概念上是有效的。
  • @Anthony 全局变量全局变量之间是有区别的,它们可以从程序中的任何地方访问(因此是全局的)和文件范围变量。静态的,只能从声明它们的文件内部访问。后者并不是真正的坏习惯,除了在一些多线程场景中。您评论中的示例都应使用文件范围变量实现。
  • 所以现在你试图说每个全局都应该是一个文件范围变量,这在嵌入式世界中尤其是不正确的,除非你认为所有代码都应该在一个文件中。你怎么能知道你从未见过的代码中变量的范围?实现共享资源的 RTOS 任务非常常见,您永远不会将多个完全不相关的任务放在同一个文件中。我很想看到一种无需全局信号量即可控制对该资源的访问的方法。这只是一个全局变量非常有用的例子;还有很多其他的。
  • @Anthony 私有封装的全部意义在于:您不应该在使用它们的文件之外查看或关心这些变量。应该通过 setter/getter 函数(可能是内联的)来访问这些变量。属于特定模块的数据应该分配在该模块中,如果需要,信号量的处理很可能也可以放在 setter/getter 函数中。信号量本身实际上就是这一原则的完美示例:您不知道或不需要知道它们在内部是如何处理的。
【解决方案3】:

如果变量是:

int foo;

在您声明的第二个 C 文件中:

extern int foo;

【讨论】:

    【解决方案4】:
    1. 尽量避免使用全局变量。如果您必须使用全局变量,请参阅其他答案。
    2. 将其作为参数传递给函数。

    【讨论】:

    • 那你如何处理中断呢?假设一个中断被触发,我想读取一个引脚上的值,如何在不将其写入全局变量的情况下返回该值?
    • @realityinabox — 这是一个令人难以置信的特定领域的答案,而 OP 的问题要广泛得多。在这种情况下,您很可能需要一个全局变量。 (这是一个非常古老的答案,我省略了很多关于为什么——线程、重入、代码可读性——以及为什么全局通常不是最佳选择的细节。)
    • @Thanatos 这不是什么“难以置信”。除非您认为嵌入式开发的广阔世界是初学者永远不会询问的东西,否则您的答案太狭隘和具体。如果有这样的事情,除了您显然认为是 C 的正常使用之外,还有许多其他原因使用全局变量。最后,OP的问题绝对没有上下文,所以你关于它的广泛陈述是一个假设。 OP 很可能一直在询问中断。
    • @realityinabox 请您详细说明为什么在泛型中应该避免全局变量?
    • @Thanatos 当人们说事情/应该/以某种方式而不说明原因时,这真的让我很恼火,这对于任何阅读它的人来说都是完全没有价值的信息,如果该功能存在,那么它打算被使用.
    【解决方案5】:

    其他变量必须声明为 public(使用 extern,public 用于 C++),并且您必须包含该 .c 文件。不过,我建议创建适当的 .h 文件来定义所有变量。

    例如,对于 hello.c,您将拥有一个 hello.h,而 hello.h 将存储您的变量定义。然后另一个 .c 文件,例如 world.c 将在顶部有这段代码:

    #include "hello.h"
    

    这将允许 world.c 使用在 hello.h 中定义的变量

    不过,它比这稍微复杂一些。您可以使用 来包含在您的操作系统路径上找到的库文件。作为初学者,我会将所有文件放在同一个文件夹中并使用“”语法。

    【讨论】:

      【解决方案6】:

      第二个文件需要知道你的变量是否存在。为此,您需要再次声明该变量,但在其前面使用关键字extern。这告诉编译器该变量可用但在其他地方声明,从而防止实例化它(再次,这会在链接时引起冲突)。虽然您可以extern 声明放在C 文件本身中,但通常的样式是为每个.c 文件提供一个随附的标头(即.h)文件,该文件向其他人提供函数或变量持有extern 声明。这样您就可以避免复制extern 声明,尤其是当它用于多个其他文件时。这同样适用于函数,尽管您不需要为它们使用关键字 extern

      这样您将至少拥有三个文件:声明变量的源文件,它是执行extern 声明的伴随标头和#includes 标头以访问导出变量的第二个源文件(或在标题中导出的任何其他符号)。当然,在尝试链接类似的东西时,您需要所有源文件(或适当的目标文件),因为链接器需要解析符号,这只有在链接的文件中实际存在时才有可能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多