在多檔案專案中,extern 常用於跨編譯單元共享全域變數。但對於陣列,其連結行為有別於一般變數,容易踩坑。
File1.cpp 定義:
int extern_array[] = {1,2,3,4,5};
int extern_array_normal[] = {10,20,30,40,50};
const int extern_array_normal_const[] = {100,200,300,400,500};
File2.cpp 使用:
extern int extern_array[];
extern int extern_array_normal[];
extern const int extern_array_normal_const[];
int main() {
// 正常存取
int first = extern_array_normal[0];
int second = extern_array_normal[1];
// ...
}
extern int *extern_array; // 注意:這是指標,非陣列
若在另一檔案定義 int extern_array[] = {...};,而此處宣告為 extern int *extern_array;,連結器會將陣列首地址視為指標值。此時 extern_array[index] 相當於 *(extern_array + index),但 extern_array 本身儲存的是首元素地址,導致解參考錯誤地址(通常極小,觸發段錯誤)。
| 定義端 | 宣告端 | 說明 |
|---|---|---|
int arr[] = {1,2,3}; | extern int arr[]; | 標準做法,編譯器自動推導大小 |
int arr[3] = {1,2,3}; | extern int arr[3]; | 明確指定大小 |
int arr[] = {1,2,3}; | extern int *arr; | 錯誤:類型不匹配,導致未定義行為 |
若必須以指標形式存取,可在定義檔額外提供一個指標變數:
// File1.cpp
int arr[] = {1,2,3};
int *arr_ptr = arr; // 額外匯出指標
// File2.cpp
extern int *arr_ptr; // 直接使用指標
int val = arr_ptr[1]; // 正常運作
extern 陣列宣告不寫大小(extern int arr[];)最安全。extern int *arr;),除非定義端確實定義為指標。const 陣列預設具有內部連結,跨檔案需在定義與宣告處均加上 extern。