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()的调用),那么一切都会很好。 到底是怎么回事?

Bruce asked 2020-02-22T10:27:41Z
5个解决方案
44 votes

您描述了3种情况:

  1. 包含2个int i = 100;文件,标头中包含file1.c
  2. 包含2个int i = 100;文件,并且标头中包含file1.c(或任何其他值;这无关紧要)。
  3. 在头文件中包含1 int i = 100;文件和file1.c

在每种情况下,想象一下将头文件的内容插入到int i = 100;文件中,然后将此file1.c文件编译到main()文件中,然后将它们链接在一起。

然后发生以下情况:

  1. 由于已经提到了“临时定义”,因此可以正常工作:每个int i = 100;文件都包含其中一个,因此链接器说“确定”。

  2. 不起作用,因为两个int i = 100;文件都包含一个带有值的定义,这些定义会发生冲突(即使它们具有相同的值)-在给定时间链接在一起的所有file1.c文件中可能只有一个具有任何给定名称的文件。

  3. 当然可以,因为您只有一个int i = 100;文件,因此没有发生冲突的可能性。

恕我直言,干净的东西是

  • int i = 100;或仅file1.c放入头文件中,
  • 然后将i的“真实”定义(即int i = 100;)放入file1.c。在这种情况下,该初始化在程序开始时使用,并且可以省略main()中的相应行。 (此外,我希望命名仅是示例;请不要在实际程序中将任何全局变量命名为i。)
glglgl answered 2020-02-22T10:28:52Z
33 votes

不要在标头中初始化变量。 将声明放在标头中,并在c文件之一中进行初始化。

在标题中:

extern int i;

在file2.c中:

int i=1;
Piotr Praszmo answered 2020-02-22T10:29:21Z
9 votes

您不应在头文件中定义全局变量。 您可以在头文件中将它们声明为int i;,并在.c源文件中对其进行定义。

(注意:在C中int i;是一个暂定定义,如果找不到该变量的其他定义,它将为该变量分配存储(=是一个定义)。)

ninjalj answered 2020-02-22T10:29:46Z
1 votes

不要在头文件中定义varibale,在头文件中进行声明(好的做法)..在您的情况下,它可以工作,因为有多个弱符号..了解弱符号和强符号.... link:[http://csapp.cs .cmu.edu / public / ch7-preview.pdf]

这种类型的代码在移植时会产生问题。

Anand Nekkunti answered 2020-02-22T10:30:11Z
1 votes

@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 **的定义。 我确实理解为什么作者更喜欢在标头中包含该定义,而不是将其放入特定的源文件中,但是我不确定该实现是否如此优雅。

Nicolas Garnier answered 2020-02-22T10:30:54Z
translate from https://stackoverflow.com:/questions/8108634/global-variables-in-header-file