为什么我必须重新解释指针指针?

时间:2018-09-21 18:11:45

标签: c++ void-pointers reinterpret-cast static-cast double-pointer

因此,此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);

如果我不更改它,则会收到错误消息:

  

错误C2440:static_cast:无法从int **转换为void **   注意:指向的类型无关。转换需要reinterpret_cast,C样式强制转换或函数样式强制转换

所以我认为问题是“类型无关”。但是,我仍然不明白,如果从int*void*可以吗,它们如何与int**void**无关?

2 个答案:

答案 0 :(得分:7)

intvoid毫无关系。 int**void**也是一样,因此无法使用static_cast进行转换。

void*特殊。尽管没有与int*相关的类型,任何数据指针类型(包括static_cast)都可以void*void并返回{{1} }不需要强制转换,因为它是隐式的)。 void*没有此属性,int*也没有void**之外的任何其他指针。


已授予void*的其他自由带有附加的限制。 void*不能被间接使用,也不能与指针算法一起使用。这些限制是唯一可能的,因为永远不会有void*类型的对象。或者从相反的角度来看,由于这些限制,void的对象不存在。

不能给予

void这些自由,因为不能给予相同的限制。不能赋予这些限制,因为void**对象确实存在并且需要存在。如果我们不能间接或迭代void*,那么就不能使用void**数组。

答案 1 :(得分:0)

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 ...),但在其他方面具有相同的含义。 / p>

回到C和C ++中的声明语法:

指向int的指针的声明为int (*pi);(括号没有用,但有助于说明这一点),您可以这样阅读:我声明表达式(*pi)的类型为{{ 1}}。您可以这样阅读函数声明:在int中,我声明如果int f(int i);的类型为i,则int的类型为f(i)

声明int看起来像是指向void (*pi);的指针,但没有类型为void的对象,表达式void也不是很好形成,这没有任何意义。在类型系统中,这是特殊情况:语法为“指向无效指针”,语义为“指向某物的指针”。

在C和C ++中,指针对象是第一类对象,您可以获取其地址并具有指向指针的指针等。(与Java相比,在Java中,像其他基本类型这样的引用不是类对象)。 / p>

因此,您可以拥有*piint** ...的指针(指向int***的指针);出于相同的原因,您可以使用int:像指针一样指向(指向void的指针),从语义上来说,指向指针(指向某物的指针)。

就像没有转换的情况一样,指向void**的指针不能分配给指向int的指针:

float

由于类型不匹配,无法将与float *f = &i; // ill-formed 不同的类型分配给void**取消引用void**的结果必须为{{1 }}对象