这里给的错误讯息不明确, 推文中提到的型别检查变严格也不是原
因. 在讲原因前先来了解赋値/初始化叙述最重要的几个要素:
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++ 是
两个 (只有) 语法相似但本质不同的语言.