2013-07-01 20 views
9

我跑一起編譯爲以下代碼:gcc A.c B.c -o combinedEXTERN在多個文件和可能的雙重定義

程序A:

#include<stdio.h> 
int a=1; 
int b; 
int main() 
{ 
extern int a,b; 
fun(); 
printf("%d %d\n",a,b); 
} 

方案B:

int a; 
int b=2; 
int fun() 
{ 
printf("%d %d\n",a,b); 
return 0; 
} 

在運行「結合「方案輸出爲:

1 2 
1 2 

現在,我已經約了幾個疑點這一個:

  1. 爲什麼不是輸出:

  2. 不是和b定義了兩次?

請清楚解釋這些,我在理解extern時遇到了很多問題,而且這些疑問中有一些不時出現。

在此先感謝。

+1

你試圖欺騙編譯器和編譯器欺騙你。 –

+5

這不是關於欺騙編譯器,而是關於讓概念正確。 – tapananand

回答

3

所以,我在很長一段時間後回答了我自己的問題。雖然聲明:

int b;是decalaration和int b = 2;是定義

是正確的,但每個人的理由是給目前尚不清楚。

如果沒有int b = 2;int b;是一個定義,那麼有什麼區別?

區別在於鏈接器處理多個符號定義的方式。 有一個弱和強符號的概念。

彙編程序將此信息隱式地編碼到可重定位目標文件的符號表中。函數和初始化的全局變量會得到強大的符號。未初始化的全局變量得到弱符號。

所以在Program Aint a = 1是一個強大的象徵,同時int b;是一個弱符號,同樣在Program Bint b = 2是一個強有力的象徵,而int a較弱。

鑑於這種觀念強,弱符號,Unix鏈接使用以下規則處理多重定義的符號:

  1. 多個強符號是不允許的。
  2. 給定一個強符號和多個弱符號,選擇強符號。
  3. 給定多個弱符號,選擇任何弱符號。

所以,現在我們可以爭論上述情況發生了什麼。

  1. 其中int b = 2int b,前者是一個強有力的符號而所以B與值2
  2. 其中int a = 1int a定義後者是弱,一個被定義爲1(相同的推理)。

因此,輸出1 2

1

據我所知: 輸出將是1 2和1 2,因爲您將a和b定義爲主函數中的外部變量。所以它也會嘗試從其他文件中獲取值。 至於第二個問題,我認爲編譯器正在對變量進行初始化併合並它們,因爲a和b在兩個文件中都被定義爲全局變量。 如果兩者都在函數內部定義,則情況可能不同。 歡迎任何建議或其他意見。

3

因爲變量在這裏沒有定義兩次;他們雖然被宣佈兩次。這些函數從變量的定義中獲取值而不是從變量的聲明中獲取。

一個聲明引入了一個標識符並描述了它的類型。通過聲明,我們向編譯器保證這個變量或者函數已經在程序中的其他地方被定義了,並且會在鏈接時被提供。 如對實施例的聲明是:

extern int a;

甲定義實際上實例化/實現此標識符。 的定義是: int a=5;int a;

備查剛看了on this link

there is this wonderful發佈在stackoverflow上。

extern告訴變量超出定義的編譯器,以便它看起來功能外還有它發現:

int a=1在節目A和int b=2在節目B

對於AUTO變量:

int a;//both definition and declaration

有關存儲類的進一步瞭解,您可以follow this link

int a主要或任何其他函數的外部是聲明(即GLOBAL)只在其所謂的函數內定義。

+0

據我所知int a;是聲明和定義,並且事實上在任何函數之外,它也變爲具有值0的初始值。 考慮: int main() { int a; //聲明和定義... int a = 5; //給出錯誤的多重定義。 } 您也可以對外部變量嘗試相同的操作。 – tapananand

+0

雅,我知道區別,但我說的是寫int a;既聲明和定義,即爲a分配內存。在任何函數之外,它還用一個定義好的值(0)初始化它,而不是垃圾值。 – tapananand

+0

對不起,遲了有功率問題....你說的可能是真實的自動變量,但不是外部變量,只要看看我的答案中的鏈接。 – 0decimal0

5

只要聲明彼此一致並與定義一致,就可以多次聲明一個變量。它可以在許多模塊中聲明,包括模塊在哪裏定義,甚至在同一個模塊中多次。

一個外部變量也可以在函數內聲明。在這種情況下,必須使用extern關鍵字,否則編譯器會認爲它是局部變量的定義,它具有不同的作用域,生命週期和初始值。這個聲明只會在函數內部而不是整個函數的模塊中可見。

現在讓我再次重複的的extern定義,說:「外部變量是一個變量DEFINED任何功能塊外」(請仔細閱讀BOLD給定的詞)。 所以對於Programe Aa有定義,但b只是聲明,以便將的extern尋找它這是在Programe B。所以從打印給出Programe A定義的「B」是1 2。現在讓我們來談談Programe B具有聲明a和定義b,所以它從programe A價值a和價值b從當前文件。

+0

據我所知int a;是聲明和定義,並且事實上在任何函數之外,它也變爲具有值0的初始值。 考慮: int main() { int a; //聲明和定義... int a = 5; //給出錯誤的多重定義。 } 您也可以對外部變量嘗試相同的操作。 – tapananand

+1

@TapanAnand當定義不可用時發生默認初始化。但在你的情況下'a'和'b'都是正確聲明和定義的,所以編譯器不會再次初始化它們,所有這些都是爲了避免多重定義錯誤。 –

+0

好的,所以int b;在Prog中A可能不是一個初始化,但它必須是定義,那麼爲什麼編程B中的int b = 2不會導致錯誤? – tapananand

相關問題