c-标头fi中的全局变量
我有2个模块(.c文件)和一个.h头文件:
file1.c:
#include <stdio.h>
#include "global.h"
int main()
{
i = 100;
printf("%d\n",i);
foo();
return 0;
}
文件2.c
#include <stdio.h>
#include "global.h"
void foo()
{
i = 10;
printf("%d\n",i);
}
全局
int i;
extern void foo()
当我做gcc file1.c file2.c时,一切正常,我得到了预期的输出。 现在,当我在头文件中将变量“ i”初始化为0并再次编译时,出现链接器错误:
/tmp/cc0oj7yA.o:(.bss+0x0): multiple definition of `i'
/tmp/cckd7TTI.o:(.bss+0x0): first defined here
如果我只是在头文件即gcc file1.c中通过初始化来编译file1.c(删除对foo()的调用),那么一切都会很好。 到底是怎么回事?
您描述了3种情况:
- 包含2个
int i = 100;
文件,标头中包含file1.c
。 - 包含2个
int i = 100;
文件,并且标头中包含file1.c
(或任何其他值;这无关紧要)。 - 在头文件中包含1
int i = 100;
文件和file1.c
。
在每种情况下,想象一下将头文件的内容插入到int i = 100;
文件中,然后将此file1.c
文件编译到main()
文件中,然后将它们链接在一起。
然后发生以下情况:
由于已经提到了“临时定义”,因此可以正常工作:每个
int i = 100;
文件都包含其中一个,因此链接器说“确定”。不起作用,因为两个
int i = 100;
文件都包含一个带有值的定义,这些定义会发生冲突(即使它们具有相同的值)-在给定时间链接在一起的所有file1.c
文件中可能只有一个具有任何给定名称的文件。当然可以,因为您只有一个
int i = 100;
文件,因此没有发生冲突的可能性。
恕我直言,干净的东西是
- 将
int i = 100;
或仅file1.c
放入头文件中, - 然后将i的“真实”定义(即
int i = 100;
)放入file1.c
。在这种情况下,该初始化在程序开始时使用,并且可以省略main()
中的相应行。 (此外,我希望命名仅是示例;请不要在实际程序中将任何全局变量命名为i
。)
不要在标头中初始化变量。 将声明放在标头中,并在c
文件之一中进行初始化。
在标题中:
extern int i;
在file2.c中:
int i=1;
您不应在头文件中定义全局变量。 您可以在头文件中将它们声明为int i;
,并在.c
源文件中对其进行定义。
(注意:在C中int i;
是一个暂定定义,如果找不到该变量的其他定义,它将为该变量分配存储(=是一个定义)。)
不要在头文件中定义varibale,在头文件中进行声明(好的做法)..在您的情况下,它可以工作,因为有多个弱符号..了解弱符号和强符号.... link:[http://csapp.cs .cmu.edu / public / ch7-preview.pdf]
这种类型的代码在移植时会产生问题。
@glglgl已经解释了为什么您尝试执行的操作不起作用。 实际上,如果您确实打算在标头中定义变量,则可以使用一些预处理程序指令进行欺骗:
file1.c:
#include <stdio.h>
#define DEFINE_I
#include "global.h"
int main()
{
printf("%d\n",i);
foo();
return 0;
}
file2.c:
#include <stdio.h>
#include "global.h"
void foo()
{
i = 54;
printf("%d\n",i);
}
global.h:
#ifdef DEFINE_I
int i = 42;
#else
extern int i;
#endif
void foo();
在这种情况下,仅在定义DEFINE_I的编译单元中定义i
,并在其他任何地方声明。 链接器没有抱怨。
在标题中声明枚举之前,我已经看过几次了,下面是包含相应标签的char **的定义。 我确实理解为什么作者更喜欢在标头中包含该定义,而不是将其放入特定的源文件中,但是我不确定该实现是否如此优雅。