【问题标题】:In C, how do I restrict the scope of a global variable to the file in which it's declared?在 C 中,如何将全局变量的范围限制在声明它的文件中?
【发布时间】:2010-11-06 00:03:12
【问题描述】:

我是 C 新手。我面前有一本书,它解释了 C 的“文件范围”,包括示例代码。但是代码只声明和初始化了一个文件范围的变量——它不会通过例如尝试以非法方式访问它来验证变量的范围。所以!本着科学的精神,我构建了一个实验。

文件bar.c

static char fileScopedVariable[] = "asdf";

文件foo.c

#include <stdio.h>
#include "bar.c"

main()
    {
    printf("%s\n", fileScopedVariable);
    }

根据我的书和 Google,对 printf() 的调用应该会失败 - 但它不会。 foo.exe输出字符串“ASDF”并正常终止。我非常想使用文件范围。我错过了什么?

【问题讨论】:

  • 调用使用静态“文件范围”定义的变量是用词不当。它仅限于单个翻译单元,这是递归粘贴到所有#included 文件中的结果。

标签: c scope


【解决方案1】:

你#included bar.c,它的作用是导致预处理器在编译器接触它之前将bar.c的内容复制到foo.c中。

尝试摆脱包含,但告诉您的编译器编译这两个文件(例如gcc foo.c bar.c)并按照您的预期观察它。

编辑:我想主要的混淆是在编译器和预处理器之间。语言规则由编译器强制执行。预处理器在编译器之前运行,并作用于那些以# 为前缀的命令。预处理器所做的只是处理纯文本。它不会解析代码或尝试以任何方式解释代码的含义。 “#include”指令非常字面化——它告诉预处理器“在此处插入该文件的内容”。这就是为什么您通常只在 .h(头文件)文件上使用 #include,并且只将函数原型和外部变量声明放在头文件中。否则,你最终会编译相同的函数,或者定义相同的变量,多次,这是不合法的。

【讨论】:

    【解决方案2】:

    这是由混淆的术语引起的。 C 中的file scope 并不是指将标识符的链接限制为仅一个翻译单元。这也不意味着范围仅限于一个物理文件。相反,file scope 表示您的标识符是全局的。这里的术语file 指的是处理所有#include#define 和其他预处理器指令的文本。

    一般来说,范围只是一个在一个翻译单元内生效的概念。当涉及多个编译时,链接开始发生。

    如果您声明文件范围变量static,那么它会提供变量内部链接,这意味着它在该翻译单元之外是不可见的。

    如果你没有明确声明它是静态的,或者如果你声明了文件范围变量extern,那么它对其他翻译单元是可见的:如果他们声明了一个具有相同标识符的文件范围变量,将将该标识符 链接 到同一个变量。

    在您的情况下,将bar.c 包含到foo.c 中会将fileScopeVariable 的定义插入到正在编译的翻译单元中。因此,它在该单元中是可见的。

    【讨论】:

      【解决方案3】:

      不要永远 #include 一个 .c 文件,就像你正在做的那样。该语言允许这样做,但 C 编码人员就是不这样做,所以如果你这样做,你会迷惑人们。很可能包括你自己。

      “#include”的意思是“编译器,在你开始编译我的代码之前,请转到另一个文件并将它粘贴到这个文件的前面。”

      我曾经因为一个 vxWorks 源文件这样做而迷茫了一整天。我仍然对他们抱怨。

      【讨论】:

      • 什么是“他们的采购订单”?
      • 我相信未来头文件会完全脱离 c,因为它们已经离开了所有理智的现代编程语言。它们之所以存在,是因为 C 无法控制包含标头的 typedef 和宏的范围。 C 需要使宏仅在声明它们的范围内可见,就像 typedef 已经做的那样。标头是大多数 C 代码难以理解的原因:冗余包含使得很难遵循控制流,其中包括做什么,并且所有范围都被不相关的全局定义和 typedef 污染。
      • @Dmitry - 他们可能会说你是个梦想家。但你不是唯一一个。
      【解决方案4】:

      删除第二个包含指令。正如上面所说的......

      在编译您的代码之前,编译器会对其进行预处理。在那个阶段,它会处理所有以“#”开头的指令,例如#include、#define 等。

      要查看该阶段的结果,您只需运行“gcc -E”(如果您使用的是 gcc)。

      【讨论】:

        猜你喜欢
        • 2014-05-10
        • 2017-08-19
        • 2020-04-03
        • 1970-01-01
        • 2010-10-30
        • 2011-11-25
        • 2017-07-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多