如果我在同一目錄中有一個包含以下 3 個檔案的專案:
mylib.h:
int some_global;
void set_some_global(int value);
mylib.c:
#include "mylib.h"
void set_some_global(int value)
{
some_global = value;
}
主檔案:
#include <stdio.h>
#include "mylib.h"
int main()
{
set_some_global(42);
printf("Some global: %d\n", some_global);
return 0;
}
我編譯
gcc main.c mylib.c -o prog -Wall -Wpedantic
我沒有收到錯誤或警告,prog程式列印42到控制臺。
當我第一次嘗試這個時,我預計會有一個“多重定義”錯誤或某種警告,因為頭檔案中some_global沒有宣告extern。在研究這個問題時,我發現在 C 中extern,函式外部的變數宣告是隱式的(而且 C 的情況正好相反,這可以通過在上面的編譯行中使用g 而不是來證明gcc)。此外,如果我將行mylib.h從宣告更改為定義(例如int some_global = 1;),我確實會收到我預期的“多重定義”錯誤(這并不令人震驚)。
我的主要問題是: 定義的變數在哪里?它似乎在某處隱式定義,但是編譯器或聯結器在什么時候意識到它需要定義該變數并且這樣做?
另外,為什么如果我extern在mylib.h檔案中顯式宣告變數,除非我在一個且只有一個中顯式宣告變數,否則我會收到“未定義參考”錯誤*.c?我希望鑒于上述代碼有效的原因(即extern隱式),明確宣告extern不會產生任何影響。為什么在行為上存在差異?
跟進
After the answer below corrected me that the code in mylib.h is a "tentative definition" rather than a declaration, I discovered this related answer with more details on such matters:
https://stackoverflow.com/a/3095957/7007605
uj5u.com熱心網友回復:
您的代碼編譯和鏈接沒有錯誤只是因為您使用
gccwhich 是用-fcommon命令列選項編譯的“-fcommon 將未初始化的全域變數放在公共塊中。這允許聯結器將不同編譯單元中相同變數的所有暫定定義決議為相同的物件,或非暫定的定義。(...) 主要用于使遺留代碼能夠無錯誤地鏈接。” 這是版本 10 之前的默認設定,但即使是現在,許多工具鏈仍在構建時啟用此選項。永遠不要在頭檔案中定義資料。只
extern在頭檔案中放置變數的定義。
它應該是:
extern int some_global;
void set_some_global(int value);
mylib.c:
#include "mylib.h"
int some_global;
void set_some_global(int value)
{
some_global = value;
}
主檔案:
#include <stdio.h>
#include "mylib.h"
int main()
{
set_some_global(42);
printf("Some global: %d\n", some_global);
return 0;
}
uj5u.com熱心網友回復:
int some_global;是一個暫定的定義。在版本 10 之前的 GCC 中,GCC 生成了一個目標檔案,將其視為通用符號。(此行為仍可通過開關選擇-fcommon。)聯結器將公共符號的多個定義合并為單個定義。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/341510.html
標籤:c storage declaration extern
上一篇:WindowsAzure應用服務出錯:請手動安裝sqlite3包
下一篇:c中使用函式和結構的復數計算器
