为什么我必须 reinterpret_cast 指针指针?
Why do I Have to reinterpret_cast Pointer Pointers?
所以这个static_cast
代码是完全合法的:
int n = 13;
void* pn = static_cast<void*>(&n);
void** ppn = &pn;
然而这必须做成reinterpret_cast
才能编译:
int n = 13;
int* foo = &n;
void** bar = static_cast<void**>(&foo);
如果我不更改它,我会收到错误消息:
error C2440: static_cast
: cannot convert from int **
to void **
note: Types pointed to are unrelated; conversion requires reinterpret_cast
, C-style cast or function-style cast
所以我认为问题是 "the types are unrelated"。但是我仍然不明白,如果从 int*
到 void*
没关系,它们怎么可能与 int**
和 void**
无关?
int
与 void
没有任何关系。 int**
和 void**
也是如此,因此它们无法使用 static_cast
.
进行转换
void*
然而,是特别。任何数据指针类型(包括 int*
)都可以 static_cast
转换为 void*
并返回,尽管没有类型与 void
相关(更进一步,转换为 void*
不需要强制转换,因为它是隐式的)。 int*
没有这个 属性,void**
也没有,除了 void*
.
也没有任何其他指针
授予 void*
的额外自由带有额外的限制。 void*
不能间接使用,也不能与指针运算一起使用。这些限制是唯一可能的,因为永远不会有 void
类型的对象。或者从相反的角度来看,由于这些限制,void
的对象无法存在。
void**
不能给予这些自由,因为它不能给予同样的限制。它不能被赋予这些限制,因为 void*
对象确实存在并且它们需要存在。如果我们不能间接或迭代 void**
,那么我们就不能使用 void*
的数组。
void* pn = static_cast<void*>(&n);
是隐式转换;你也可以写
void *pn = &n;
表示pn
存储了一个指向某个对象类型的指针;程序员有责任知道该对象类型是什么。要回退,您需要 static_cast
:
int *pi = static_cast<int*>(pn);
请注意,使用 static_cast
转换为与原始类型有显着差异的任何类型(float
有显着差异,const int
则没有)是一种重新解释的方式。您应该拼写 reinterpret_cast
而不是隐式转换(或 static_cast
),然后是 static_cast
。
这就是 void*
的全部目的,一个可以追溯到 C 的概念,其中强制转换显然是 C 风格的强制转换(不是 static_cast
...),但在其他方面具有相同的含义.
回到C和C++中声明的语法:
指向int
的指针的声明是int (*pi);
(括号没用但有助于说明这一点),你可以这样读:我声明表达式(*pi)
有类型int
。您可以这样阅读函数声明:在 int f(int i);
中,我声明如果 i
具有类型 int
,则 f(i)
具有类型 int
.
声明 void (*pi);
看起来像一个指向 void
的指针,但不存在 void
类型的对象,表达式 *pi
不是即使格式正确,也没有意义。这是类型系统中的 特例 :语法表示 "pointer to void",语义表示 "pointer to something".
在 C 和 C++ 中,指针对象是第一个 class 对象,您可以获取它的地址并拥有指向指针的指针等。(与 Java 相比,其他引用基本类型不是 class 对象。)
所以你可以有一个int**
, int***
... pointers to (pointers ... to int
);出于同样的原因,您可以拥有 void**
:声明为指向(指向 void 的指针)的指针,在语义上是指向(指向某物的指针)的指针。
就像指向 int
的指针不能被赋值给指向 float
的指针一样:
float *f = &i; // ill-formed
由于类型不匹配,无法将不同于 void**
的类型分配给 void**
:取消引用 void**
的结果必须是一个 void*
对象.
所以这个static_cast
代码是完全合法的:
int n = 13;
void* pn = static_cast<void*>(&n);
void** ppn = &pn;
然而这必须做成reinterpret_cast
才能编译:
int n = 13;
int* foo = &n;
void** bar = static_cast<void**>(&foo);
如果我不更改它,我会收到错误消息:
error C2440:
static_cast
: cannot convert fromint **
tovoid **
note: Types pointed to are unrelated; conversion requiresreinterpret_cast
, C-style cast or function-style cast
所以我认为问题是 "the types are unrelated"。但是我仍然不明白,如果从 int*
到 void*
没关系,它们怎么可能与 int**
和 void**
无关?
int
与 void
没有任何关系。 int**
和 void**
也是如此,因此它们无法使用 static_cast
.
void*
然而,是特别。任何数据指针类型(包括 int*
)都可以 static_cast
转换为 void*
并返回,尽管没有类型与 void
相关(更进一步,转换为 void*
不需要强制转换,因为它是隐式的)。 int*
没有这个 属性,void**
也没有,除了 void*
.
授予 void*
的额外自由带有额外的限制。 void*
不能间接使用,也不能与指针运算一起使用。这些限制是唯一可能的,因为永远不会有 void
类型的对象。或者从相反的角度来看,由于这些限制,void
的对象无法存在。
void**
不能给予这些自由,因为它不能给予同样的限制。它不能被赋予这些限制,因为 void*
对象确实存在并且它们需要存在。如果我们不能间接或迭代 void**
,那么我们就不能使用 void*
的数组。
void* pn = static_cast<void*>(&n);
是隐式转换;你也可以写
void *pn = &n;
表示pn
存储了一个指向某个对象类型的指针;程序员有责任知道该对象类型是什么。要回退,您需要 static_cast
:
int *pi = static_cast<int*>(pn);
请注意,使用 static_cast
转换为与原始类型有显着差异的任何类型(float
有显着差异,const int
则没有)是一种重新解释的方式。您应该拼写 reinterpret_cast
而不是隐式转换(或 static_cast
),然后是 static_cast
。
这就是 void*
的全部目的,一个可以追溯到 C 的概念,其中强制转换显然是 C 风格的强制转换(不是 static_cast
...),但在其他方面具有相同的含义.
回到C和C++中声明的语法:
指向int
的指针的声明是int (*pi);
(括号没用但有助于说明这一点),你可以这样读:我声明表达式(*pi)
有类型int
。您可以这样阅读函数声明:在 int f(int i);
中,我声明如果 i
具有类型 int
,则 f(i)
具有类型 int
.
声明 void (*pi);
看起来像一个指向 void
的指针,但不存在 void
类型的对象,表达式 *pi
不是即使格式正确,也没有意义。这是类型系统中的 特例 :语法表示 "pointer to void",语义表示 "pointer to something".
在 C 和 C++ 中,指针对象是第一个 class 对象,您可以获取它的地址并拥有指向指针的指针等。(与 Java 相比,其他引用基本类型不是 class 对象。)
所以你可以有一个int**
, int***
... pointers to (pointers ... to int
);出于同样的原因,您可以拥有 void**
:声明为指向(指向 void 的指针)的指针,在语义上是指向(指向某物的指针)的指针。
就像指向 int
的指针不能被赋值给指向 float
的指针一样:
float *f = &i; // ill-formed
由于类型不匹配,无法将不同于 void**
的类型分配给 void**
:取消引用 void**
的结果必须是一个 void*
对象.