※ 引述《justhere (發廢文就是生活的小確幸)》之銘言:
: 各位好,小弟新手,
: 目前在看C++ primier fifth edition,
: 進度到variable的定義與宣告這個小節,
: 在講extern 這個keyword時書中舉一個小範例:
: extern int i; // declares but does not define i
: int j; // declares and defines i
: 他解釋
: To obtain a declaration that is not also a definition,
: we add extern keyword and may not provide an explicit initializer
: 請問具體來說c++中initializer所做的事情是什麼呢?
: 是分配記憶體位置和值給該name嗎?
: 感謝
先不管 extern, 在語法上 int i; 這樣寫就是宣告. 而對於非函式
的宣告來說, 即使我們可以不寫 initializer, 但物件一定得經過
初始化, 而依照這個物件被宣告的地方, 會有不同的初始化行為,
有 static storage 如全域 int 物件, 就會經過 zero-initializ-
ation (效果等同於 = 0, 和 memset(&obj, 0, sizeof(obj)) 意義
不同), 如果是區域 int 物件則不給初始值; 但無論給不給初始值,
物件被宣告的當下, 它的實體即存在於該 TU (translation unit)
裡 (這個結果才是書中說的定義)
在宣告前方加上 extern 修飾符語意就變了, 這時不為了創造物件
實體, 而是想在當下能重複使用某處宣告過的物件 (可以存在同個
TU 或別的 TU), 而跨 TU 存取的情況下, 這個物件必須要具備
external linkage 才行. 考慮以下程式碼, 請問印出的 i 值是多
少?
// translation unit #1
static int i = 1;
namespace ns {
int i = 2;
}
// translation unit #2
void foo() {
extern int i; // declare i but i is not defined in foo()
std::cout << "i = " << i << std::endl;
}
以上是陷阱題, 在 TU #2 裡面雖然預期會有個 i 宣告在全域底下
, 結果因為在 TU #1 裡全域的 i 宣告有加上 static 修飾符所以
無法在別的 TU 裡使用. 這段程式碼會造成連結錯誤.
加了 extern 的宣告還是有辦法回復原本宣告的功能, 只要明確地
用 initializer 初始化即可; 但是這樣寫語意是矛盾的, 通常編譯
器會給警告 (這時候會忽略 extern 修飾符).
除了函式會特別把宣告還有建立實體分成兩種寫法, non-inline
static data member 也是如此:
class foo {
static int i; // declare here
};
int foo::i = 1; // define here
這時候我們不會說 static int i; 是定義: 它還是宣告, 但真正建
立實體的動作必須從 class definition 拉出來寫在命名空間內.
最後來總結幾個重點:
1. 宣告或定義要看情境, 不是單純用語法來分辨
2. 加 extern 修飾符也可定義物件
3. extern 是用來存取具有 external linkage 的物件 (跨 TU)