這裡給的錯誤訊息不明確, 推文中提到的型別檢查變嚴格也不是原
因. 在講原因前先來瞭解賦値/初始化敘述最重要的幾個要素:
B = A;
當我們要把 A 賦値給 B 的時候, 至少需要弄清楚以下 3 點:
1. A 的型別為何?
2. B 的型別為何?
3. 可不可以透過隱式轉換 (implicit conversion) 將
A 的型別轉換到B 的型別?
簡單舉個例子, 我們都知道以下的程式碼是合法的:
int i = 0;
int* pi = &i; // 1. pi's type is int*
void* pv = pi; // 2. pv's type is void*
// 3. valid, convert int* to void*
再回到原本的問題:
char* str = "hello";
在將 string literal 給 char* 物件做初始化之前, 你需要知道它
的型別是什麼, 據我所知在 C 和 C++ 內定義的型別不同:
C (n2346) https://bit.ly/2lHYvLe
6.4.5.6
The multibyte character sequence is then used to
initialize an array of static storage duration and
length just sufficient to contain the sequence. For
character string literals, the array elements have type
char, and are initialized with the individual bytes of
the multibyte character sequence.
C++ (n4830) https://bit.ly/2k3F5jL
5.13.5.6
An ordinary string literal has type “array of n const
char” where n is the size of the string as defined
below, has static storage duration, and is initialized
with the given characters.
所以你的程式碼效果其實和下面的差不多 (C++):
const char literal[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char* str = literal;
會有錯誤的原因在這:
透過隱式轉換無法將指標的 constness 給移除.
還有另外一個地方需要注意: 因為 string literal 本身是陣列,
陣列賦値/計算之前會先退化 (decay) 成指標 (也是轉型的一種),
錯誤訊息省略描述這個步驟所以很容易讓人誤解它的型別. 最後總
結一下編譯器做的事情:
1. 取得 "hello" 的型別, 為 const char[6]
2. 因為要賦値, 把 "hello" 陣列退化成 const char*
3. 取得 str 的型別, 為 char*
4. 檢查能否透過隱式轉換將 const char* 轉成 char* (失敗)
第一個步驟 C 和 C++ 編譯器取得的型別相異, 導致結果也不同,
這也是常常拿網路上的原始碼會編不過的原因, 其實 C 和 C++ 是
兩個 (只有) 語法相似但本質不同的語言.