2011-11-13 244 views
35

我有2个模块(.c文件)和一个.H头文件:全局变量

file1.c中:

#include <stdio.h> 
#include "global.h" 

int main() 
{ 
    i = 100; 
    printf("%d\n",i); 
    foo(); 
    return 0; 
} 

file2.c中

#include <stdio.h> 
#include "global.h" 

void foo() 
{ 
    i = 10; 
    printf("%d\n",i); 
} 

global.h

int i; 
extern void foo() 

当我做gcc file1.c file2.c everythin克工作正常,我得到预期的输出。现在,当我初始化变量“我”在头文件中说0和重新编译我得到一个链接错误:

/tmp/cc0oj7yA.o:(.bss+0x0): multiple definition of `i' 
/tmp/cckd7TTI.o:(.bss+0x0): first defined here 

如果我只是初始化编译file1.c中(除电话为foo())在头文件即gcc file1.c中,一切正常。到底是怎么回事?

回答

31

有3个方案中,您描述:

  1. 2个.c文件,并用int i;在头中。
  2. 有2个.c文件和int i=100;在标题(或任何其他值,这并不重要)。
  3. 用1 .c文件和int i=100;在标题中。

在每种情况下,设想插入.c文件中的标题文件的内容和此.c文件编译成.o文件,然后这些连接在一起。

然后会发生以下情况:

  1. 工作,因为已经提到的“初步定义”的罚款:每.o文件包含其中之一,因此链接器说“OK”。

  2. 不起作用,因为这两个.o文件包含一个值,该碰撞(即使它们具有相同的值)的定义 - 有可能是唯一一个与任何给定的名字在所有.o文件被链接在一起在给定的时间。

  3. 作品,当然,因为你只有一个.o文件,所以没有可能性的碰撞。

恕我直言,一个干净的事情将是

  • 把无论是extern int i;或只是int i;到头文件,
  • ,然后把我的“真实”的定义(即int i = 100;)成file1.c。在这种情况下,在程序开始时使用该初始化,并且main()中的对应行可以省略。 (此外,我希望命名仅仅是一个例子;请不要在实际程序命名任何全局变量为i
+5

我说过什么?“把是'的extern INT I;'或'只是INT I;'进头文件”:'EXTERN INT i'是更好,因为它立刻会告诉你,如果“真实”的定义是由一些意外丢失。仅仅使用'int i',就会给'0'一个无声的定义。 – glglgl

+0

我没有得到第一个解释,你可以详细说明,因为当内存分配给变量我。直到现在我明白的是int我在global.h中相当于extern int i;这意味着这两个目标文件都有引用,这个内存是我在其他地方分配的。 – user2383973

+1

@ user2383973内存由链接器分配和保留。当它看到一个带有任务和一个“暂定”定义的请求时,一切都很好。当它看到几个作业时,即使它们具有相同的值,也不行。 – glglgl

24

不要在标题中初始化变量。将声明放入标题并初始化为c文件之一。

在标题:

extern int i; 

在file2.c中:

int i=1; 
+1

注意,OP未初始化变量,这是一个试探性的定义。 – ninjalj

+0

@Banthar:为什么它在第二种情况下工作(当我编译file1.c时)? – Bruce

+0

@Bruce:因为在这种情况下,它只被初始化一次。 – glglgl

8

在头文件中你不应该定义全局变量。您可以在头文件中声明它们为extern,并在.c源文件中定义它们。

(注:C,int i;是试探性的定义,它为变量(=是一个定义),如果有发现该变量没有其它定义分配存储空间。)

+3

参见:http://ninjalj.blogspot.com/2011/10/tentative-definitions-in-c.html – ninjalj

+0

如果我在头放的#ifndef,并宣布在头部的变量'INT了'?虽然现在我只有一个头文件的副本,但多重定义错误仍然存​​在。 – chandresh

1

不要定义头文件varibale,做头文件(好习惯)声明。 。在你的情况下,它的工作,因为多个弱符号..阅读关于强和弱符号....链接:http://csapp.cs.cmu.edu/public/ch7-preview.pdf

这种类型的代码创建问题,同时移植。

+1

你想说什么 – tod

+0

@ tod。不是最好的措辞答案,但如果你想知道他的定义/声明是什么意思,这里有一个你应该*做的完整答案http://stackoverflow.com/a/1164190/310560 – Assimilater

+0

@Assimilater哇, 谢谢 – tod