內部連結 Internal Linkage

這章我們要來介紹內部連結 internal linkage,包括它是什麼、要怎麼用它等等。

廢話不多說,就讓我們趕快來學習吧!

什麼是內部連結

不知道你們有沒有想過,為什麼在一個檔案裡面的變數只有該檔案才看得到,其他檔案看不到?

你們可能會想:「誒這不是很合理嗎?」

沒錯!這很合理!如果不是這樣的話那如果有成千上萬個檔案的話那就會非常混亂了。

但其實這個背後有一個原因,那就是內部連結!

內部連結的意義在於,如果一個變數或函數被設定為內部連結,那麼只有該檔案可以看得到它。

聰明的你可能會問,那我們什麼時候會需要其他檔案看得到它?

誒不用急,我們會在下一篇專門講解內部連結的兄弟,外部連結。這章就讓我們專心在內部連結吧!

但其實,並不是所有變數都是預設為內部連結的喔!讓我們接下來看下去。

全局變數

全局變數,中文叫做 global variable。從名字我們就可以感覺到,所有檔案都可以讀到它。

那我們應該要如何建立一個全局變數呢?

在以前,我們一直都是在 main() 函數裡面建立變數。但其實, 我們也可以在 main() 函數之外建立變數!

而在 main() 函數之外建立的變數,如果沒有額外的關鍵字,那麼就會是一個全局變數。而全局變數預設就不是內部連結!

比方說:

// 全局變數 global variable
int a{0};

int main()
{
    int b{0};

    return 0;
}

我們可以將這個全局變數改為內部連結,有兩個方法:

  • static
  • const
// 擁有內部連結的全局變數
static int a{0};
const  int c{0};

int main()
{
    int b{0};

    return 0;
}

static 這個關鍵字沒什麼好說的,就是一個強制宣稱變數擁有內部連結的機制而已。

const 是什麼?關鍵字 const 其實是 constant 的縮寫,代表固定值,也就是絕對不能夠被改變。

因此如果我嘗試改變變數 c 的值,程式就會報錯!

const int c{0};

int main()
{
    c = 3;    // 程式會報錯!
    return 0;
}

那為什麼被宣告為固定值的變數預設不能被其他文件看到呢?

其實很好理解,這是因爲其他文件並不會知道這個變數被宣告為固定值。因此可能會想要去改變它,而我們知道一但嘗試改變它,就會報錯。

我們可以做一個小實驗來證實擁有內部連結的全局變數。我們來創建兩個 .cpp 檔案:

test.cpp

const int a{1};

main.cpp

static int a{5};

int main()
{
    std::cout << a << std::endl;
    return 0;
}

我們會看到程式碼會印出數字 5。

函數

有發現嗎?我們之前在寫函數時都寫在 main() 的外面。所以函數其實預設是擁有外部連結的!

我們一樣也可以用關鍵字 static 將函數改為擁有內部連結。

test.cpp

static int print()
{
    std::cout << "This is from test.cpp" << std::endl;
}

main.cpp

static int print()
{
    std::cout << "This is from main.cpp" << std::endl;
}

int main()
{
    print();
    return 0;
}

我們可以發現結果為:

This is from main.cpp

為什麼要內部連結

其實內部連結主要提供了兩個主要好處:

  • 有一個我們想確保不被其他文件讀取的東西。這可能是一個我們不想被干擾的全局變數,或者是一個我們不希望被調用的函數。
  • 避免命名衝突。因為具有內部連結的變數或函數名稱不會暴露給連結器,因此它們只可能與在同一文件中的名稱發生衝突,而不是整個大專案中的其他幾百幾千個文件。

我個人的建議是,如果一個變數或函數並不需要被外部的文件取用的話,就一律將他們設定為擁有內部連結!

這在小型的個人專案中可能不會造成什麼影響,但在大型專案中,會大大的減少許多意想不到的錯誤的可能性!

總結

這章我們了解了一個全新的概念,內部連結,包括它為什麼存在、它長怎麼樣、它的應用等等。

這個東西其實概念不難,但我們很常在寫程式碼時忘記這個簡單又重要的規則,導致程式出錯。

下一章我們會來介紹外部連結~