【问题标题】:what is the visibility/scope of a global variable in C?C中全局变量的可见性/范围是什么?
【发布时间】:2013-04-16 13:53:55
【问题描述】:

我有两个 .c 文件:A1.c 和 A2.c

A1.c如下:

int i=0;
void main()
{}

A2.c如下:

int i=0;
void func()
{}

它编译得很好,但是当我尝试链接这两个 .o 文件时,出现“i 的多重定义”错误。 我知道i 在这里是一个全局变量,但它不需要extern 关键字才能在其他文件中使用。在我的项目中,我没有使用extern。那我怎么会报错呢?

【问题讨论】:

  • "它需要一个extern关键字才能在其他文件中使用"--嗯,亨利,全局变量的默认存储类是“extern”。所以你不需要在A1中提及.c.但是您在 A2.c 中使用它,因为这表示该变量的定义在另一个文件中,即 A1.c。
  • @SheerFish 我了解到 extern 是函数的默认值,而不是全局变量。
  • 全局变量默认有extern存储类。这里有一个StackOverflow链接,已经详细解释了stackoverflow.com/questions/4239834/…
  • 我的意思是,对于函数和全局变量都是如此,而不仅仅是函数。引用 C99 标准“5) 如果函数标识符的声明没有存储类说明符, 它的链接被完全确定,就好像它是使用存储类说明符 extern 声明的。如果对象标识符的声明具有文件范围且没有存储类说明符,则它的链接是外部的。"

标签: c linker global-variables


【解决方案1】:

在编译时,编译器将每个全局符号以强或弱的形式导出到汇编器,汇编器将此信息隐式编码到可重定位目标文件的符号表中。函数和初始化的全局变量得到强符号。未初始化的全局变量获得弱符号。

鉴于强符号和弱符号的概念,Unix 链接器使用以下规则来处理多重定义的符号:

规则 1: 不允许使用多个强符号。
规则 2: 给定一个强符号和多个弱符号,选择强符号。
规则 3: 给定多个弱符号,选择任何一个弱符号。

您的代码, A1.c如下:

int i=0; // Strong Symbol
void main() {}

A2.c如下:

int i=0; // Strong symbol
void func() {}

根据规则 1,这是不允许的。

更多详细信息:http://www.geeksforgeeks.org/how-linkers-resolve-multiply-defined-global-symbols/

【讨论】:

    【解决方案2】:

    长话短说,像

    这样的陈述
    extern int i;
    

    是一个声明,而声明

    int i=0;
    

    是一个定义

    在C语言中,你可以在一个程序中多次声明一个变量,但你只能定义一次。第一条语句向A2表示变量i的定义在另一个文件中。我不明白为什么你对使用“extern”感到非常担心。

    【讨论】:

      【解决方案3】:

      在 C 语言中,只要另一个编译单元看到它存在,就可以从另一个编译单元访问全局变量,方法是声明它extern。链接器使作业具有链接外部声明和另一个 .c 中的定义。

      如果您希望它仅对您正在编译的 .c 可见,则必须将其指定为 static

      static int i = 0;
      

      【讨论】:

      • “如果你想让它只对你正在编译的.c可见”----这不是他打算做的。他很困惑为什么如果他使用他会得到一个错误这两个文件 A1 和 A2 中的语句“int i=0”即使他为 i 分配了相同的值。
      • 好吧,我可能理解错了。我以为他想在多个.c中使用同名的全局变量
      • 好吧,如果他打算这样做,你给出的关于“静态”的建议肯定会帮助他。
      【解决方案4】:

      当然它在链接上失败了:它试图合并两个对象文件,这些文件引用了两个不同内存位置的对象。

      在这种情况下,您的变量的真正定义在您的所有源代码中必须是唯一的,并且对该变量的所有其他引用必须通过使用 external 关键字来完成(正如您所坐的那样)。

      编译不会抱怨,因为它不知道你的两个文件的关系,只有链接器必须弄清楚。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-26
        • 2010-10-07
        • 1970-01-01
        • 2014-04-05
        • 1970-01-01
        • 2016-08-19
        • 1970-01-01
        相关资源
        最近更新 更多