首頁 > 軟體

C語言連結屬性的實踐應用

2022-03-19 13:01:02

什麼是連結屬性

連結屬性與C語言中各個目標檔案及函數的連結過程有關,用於認定不同檔案的識別符號(即程式中定義的各種名稱,包括變數名、函數名)是否是同一個實體。更通俗地說,就是在兩個不同檔案中的變數、函數宣告是否指向同一個實體。比如:a、b檔案同時宣告了變數c,連結屬性就指定了這兩處變數c是否是同一個c。

簡單來說,連結屬性的作用就是讓你能在a檔案中決定要不要存取b檔案中的變數、函數。

連結屬性的分類

連結屬性有三種:

  • external - 外部連結
  • internal - 內部連結
  • none - 無連結

對於external屬性的識別符號,不同檔案中出現的多個同名稱識別符號指向同一個實體。在C語言中,用extern關鍵字在宣告中指定以參照其他檔案中定義的相同識別符號

對於internal屬性的識別符號,僅在當前檔案內該識別符號指向同一個實體。在C語言中,用static關鍵字在宣告中指定讓識別符號變為該檔案私有(只有對原本預設的連結屬性為external的識別符號,才能用static關鍵字改變其連結屬性為internal)。

對於none屬性的識別符號,在每個宣告位置都是一個新的實體。C語言中,沒有對應的關鍵字。

預設的連結屬性

識別符號的預設的連結屬性與其出現的位置有關。

  • 程式的全域性變數、所有函數預設的連結屬性為external。

  • 其餘識別符號的預設連結屬性為none。

在以下例子中,b、c、f的連結屬性就是external:

typedef char *a;
int b;
int c(int d)
{
	int e;
	int f(int g);
}

實踐應用

extern

在a檔案中想要使用b檔案中定義的external屬性識別符號,可使用extern關鍵字在a檔案中宣告。

即使該識別符號所在位置預設連結屬性為external,也建議使用extern關鍵字顯式說明,有利於增加程式可讀性。

static

在a檔案定義了一個全域性識別符號,但不想被其他檔案存取,可以對該識別符號加上static關鍵字。

在a、b檔案中定義了同樣的識別符號,通過static關鍵字可以避免多重定義問題。

再次提醒:只有對原本預設的連結屬性為external的識別符號,才能用static關鍵字改變其連結屬性為internal

一些細節

  • 對於external屬性的識別符號,你可以在多個不同原始檔中宣告,但是你只能在一處初始化。否則就會出現重複定義的問題:multiple definition of 'a';
  • extern關鍵字宣告的識別符號用於存取其他檔案中定義的同名的識別符號,因此無法進行初始化。如果你對extern宣告的變數進行初始化就會生成警告:warning: ‘a’ initialized and declared ‘extern’
  • 如果在其他檔案中不存在相應的識別符號定義,卻在當前檔案中使用了extern宣告,會報錯:undefined reference to 'a',原理同2。
  • external屬性的識別符號總是靜態儲存型別。
  • static關鍵字還有改變儲存型別的作用,因此,其作用與上下文環境有關,只有對於預設連結屬性為external的識別符號,才有改變連結屬性的作用。
  • C++中,const變數隱含的具有internal屬性,C中並不具有這一性質。

思考題

internal和none屬性除了作用域不同還有什麼區別?

以下程式碼一定程度上闡釋了部分割區別:

static int i; // definition
              // static storage
              // internal linkage

void f(void)
{
    extern int i; // declaration
                  // refers to the static i at file scope
                  // note that even though the specifier is extern
                  // its linkage is intern (this is legal in both C/C++)
    {
        int i; // definition
               // automatic storage
               // no linkage
    }
}

實際上連結屬性和作用域是兩個概念。之所以產生以上問題,因為internal屬性識別符號出現的位置都是在檔案作用域,而none往往在程式碼塊作用域。此處想引起讀者對內連線更深入的思考,見問題2。

檔案作用域已經能讓程式存取同一檔案變數,那麼再進行內部連結的意義在哪?

同一個識別符號在連結中只能存在一個,那麼通過內部連結的方式可以隔絕同名外部連結,且限定了外部編譯單元不能存取該檔案全域性識別符號。

a.c:

#include <stdio.h>

static int a=3;

int main(void)
{
    extern int a;
    printf("a=%dn", a);
    return 0;
}

b.c:

int a=1;

編譯後結果為:

a=3

以上僅為不完善的個人猜想,拋開隔絕外部連結這一點不談,就內部連結這一名稱而言,筆者對為什麼要在同一個檔案內部使用連結的設計仍然存疑,但目前該話題的答案超出了筆者的理解,因此更深入的討論暫時留白。

拓展:感興趣的同學可以嘗試學習連結相關知識,或許會找到更確定的答案。

參考

總結 

到此這篇關於C語言連結屬性的文章就介紹到這了,更多相關C語言連結屬性內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com