extern “C” 閱讀筆記

來源:互聯網
上載者:User
extern "C" 閱讀筆記
發信站: 水木社區 (Fri Mar 7 00:22:47 2008), 站內

本以為很簡單,仔細閱讀了一下 C++ 標準,發現內容還不少。總結了一下。

要點:

函數類型,函數名,變數名具有語言連結性,language linkage。

語言連結性可能會影響到名字以及呼叫慣例等,由實現決定。

C++ 預設的語言串連性是 C++ 語言連結性。

語言連結性僅作用於函數類型,函數名,變數名。

不同語言連結性的函數類型是不同的類型,即便其餘的地方都相同。

語言連結性用連結性規格(linkage-specification)來聲明,分有無大括弧兩種形式。
extern string-literal { declaration-seq opt }
extern string-literal declaration;

所有的實現都必須支援 "C" 和 "C++" 連結性。

連結性規格允許嵌套,此時最內層的那個起作用,但是並不建立範圍。
extern "C" { extern "C++" { class A{}; } }
extern "C" { class B:A{};}
因為不是範圍,B 可以看到 A

如果C連結性施加到C++類成員和成員函數的類型,忽略C連結性,但是其餘的地方依然有效,比如成員函數的參數。
比如:
extern "C" { class A{ void f(void (*p)()){} }; }
A 不是函數和變數,沒有語言連結性
f 是 C++ 成員函數,忽略所指定的 C 連結性,如果在外層沒指定別的,就是
C++連結性。
p 具有 C 連結性。

除了C++連結性的函數外,同一個函數不帶連結性規格的聲明的函數不能早於帶的。
如果前面聲明了帶連結性規格的形式,後面又出現了不帶的形式,不受影響。
比如 extern "C" void foo(); void foo(); 是可以的,反過來不行。
但是 extern void foo(); extern "C++" void foo(); 可以。

特定名字的 C 語言連結性的函數最多隻能有一個,即便放在不同的 namespace 裡,
也是同一個函數,變數也是如此。這樣的函數或變數也不能重複定義。
namespace A { extern "C" void f(); }
namespace B { extern "C" void f(); }
兩個 f 是同一個

有連結性規格的函數具有外部連結性。
因此
extern "C" void f();
static void f();
是錯誤的。

連結性規格,帶大括弧的形式,不影響裡面的聲明是聲明還是定義。
單個聲明的形式,視為 extern 限定符。
extern "C" int i; 是聲明;
extern "C" { int i; } 是定義;
extern "C" { extern int i; } 又是聲明。

單個聲明形式的串連性規格,不能再指定儲存類別。
extern "C" static void f(); // error

其他說明:
因為語言連結性只跟連結性有關,因此 C 語言連結性的函數也可以有預設參數,
函數的介面可以有引用。

標準 C++ 庫中的符號預設是 C++ 連結性。
C++ 用的標準 C 庫中的外部連結性符號可以是 C 或者 C++ 語言連結性,推薦後者。
任何帶有連續兩個底線的名字保留給實現用作同時具有 C 和 C++ 連結性的名字。

標準 C 庫中的任何函數簽名都保留給實現用來做同時具有 C 和 C++ 連結性的名字。

因為不同語言串連性的相同簽名的函數類型算作不同類型,所以可以相互重載,不算同
一個函數。
extern "C" int atexit(void (*f)(void)) // 這裡的 f 是 C 連結性
extern "C++" int atexit(void (*f)(void)) // 這裡的 f 是 C++ 連結性

類似的有兩個原型的函數還有 bsearch,qsort 等帶函數指標類型的參數的函數。

以上都是 C++ 標準裡的理論,落實到實踐上,為了實現方便,很多編譯器都把 C 和
C++ 連結性的函數的類型視為相同的類型,此時的連結性僅僅影響產生的名字,或者
還可能影響異常規格,比如把 extern "C" 的函數預設視為 throw() 的等,並不影響
呼叫慣例。同樣也為了實現的方便,C++ 所用的 C 庫中的符號也都是 C 語言連結性的,
因此這樣的情況下,atexit, bsearch, qsort 等在這些編譯器搭配的庫中也就只有一種
原型了。

這種情況下,同樣簽名的 C 和 C++ 連結性的函數類型就算做同種類型了,下邊的程式
編譯就會失敗:
void f(void (*p)())
{
}
extern "C" void f(void (*q)())
{
}

VC 和 gcc 在這一點上都是不符合標準的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.