繁体   English   中英

头文件中的全局变量

[英]Global variables in header file

我有一个 2 个模块(.c 文件)和一个 .h 头文件:

文件1.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

如果我只是用头文件中的初始化来编译 file1.c(删除对 foo() 的调用),即 gcc file1.c,一切正常。 到底是怎么回事?

有3种情况,你描述:

  1. 使用 2 个.c文件和int i; 在标题中。
  2. 使用 2 个.c文件和int i=100; 在标题中(或任何其他值;没关系)。
  3. 使用 1 个.c文件和int i=100; 在标题中。

在每种情况下,想象一下将头文件的内容插入到.c文件中,并将这个.c文件编译成一个.o文件,然后将它们链接在一起。

然后发生以下情况:

  1. 由于已经提到的“暂定定义”,工作正常:每个.o文件都包含其中之一,因此链接器说“确定”。

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

  3. 当然有效,因为您只有一个.o文件,因此不可能发生冲突。

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

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

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

在标题中:

extern int i;

在 file2.c 中:

int i=1;

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

(注意:在 C 中, int i;是一个暂定定义,如果在翻译单元中没有找到该变量的其他定义,它会为变量(= 是一个定义)分配存储空间。)

@glglgl 已经解释了为什么您尝试做的事情不起作用。 实际上,如果你真的想在头文件中定义一个变量,你可以使用一些预处理器指令来欺骗:

文件1.c:

#include <stdio.h>

#define DEFINE_I
#include "global.h"

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

文件2.c:

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

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

全球.h:

#ifdef DEFINE_I
int i = 42;
#else
extern int i;
#endif

void foo();

在这种情况下, i只在你定义DEFINE_I并声明其他地方编译单元定义 链接器没有抱怨。

我之前已经看到过几次,其中在标题中声明了一个枚举,下面是一个包含相应标签的 char** 的定义。 我确实理解为什么作者更喜欢在标题中包含该定义而不是将其放入特定的源文件中,但我不确定实现是否如此优雅。

目前接受的对这个问题的回答是错误的。 C11 6.9.2/2:

如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,则行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的末尾,初始化器等于 0。

所以问题中的原始代码表现得好像file1.cfile2.c每个都包含行int i = 0; 最后,由于多个外部定义(6.9/5)导致未定义行为。

由于这是语义规则而不是约束,因此不需要诊断。

以下是关于相同代码的另外两个问题,答案是正确的:

不要在头文件中定义变量,在头文件中进行声明(良好实践).. 在你的情况下它是有效的,因为多个弱符号.. 阅读弱符号和强符号 .... 链接: http://csapp.cs。 cmu.edu/public/ch7-preview.pdf

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM