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

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。)
answered 2020-02-22T10:28:52Z
33 votes

不要在標頭中初始化變量。 將聲明放在標頭中,并在c文件之一中進行初始化。

在標題中:

extern int i;

在file2.c中:

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

您不應在頭文件中定義全局變量。 您可以在頭文件中將它們聲明為int i;,并在.c源文件中對其進行定義。

(注意:在C中int i;是一個暫定定義,如果找不到該變量的其他定義,它將為該變量分配存儲(=是一個定義)。)

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

不要在頭文件中定義varibale,在頭文件中進行聲明(好的做法)..在您的情況下,它可以工作,因為有多個弱符號..了解弱符號和強符號.... link:[http://csapp.cs .cmu.edu / public / ch7-preview.pdf]

這種類型的代碼在移植時會產生問題。

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 **的定義。 我確實理解為什么作者更喜歡在標頭中包含該定義,而不是將其放入特定的源文件中,但是我不確定該實現是否如此優雅。

answered 2020-02-22T10:30:54Z
translate from