为什么我需要使用reinterpret_cast重新解释指针指针?

4

所以这个 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**怎么会不相关呢?

3
为什么你的第二段代码被加删除线了? - 463035818_is_not_a_number
3
你可以将&foo看作是指向int*的指针,而bar是指向void*的指针。这两种类型非常不同。正是多了一层间接性才使整个区别产生。 - Some programmer dude
4
请注意,sizeof(int*)sizeof(void*)甚至不能保证相同。 - Ben Voigt
2
@JonathanMee:如果没有内存对齐的指针(void*char*)比需要内存对齐的指针(包括int*)更大,那么来回传递的要求就可以满足。 - Ben Voigt
2
static_cast<void*>甚至不是一个显式转换,它是显式地执行的隐式转换。 - curiousguy
显示剩余12条评论
2个回答

8

intvoid没有任何关系。同样的,int**void**也不能使用static_cast进行转换。

void*特殊的。任何数据指针类型(包括int*)都可以通过static_cast转换成void*,然后再转回去,即使没有任何一种类型与void相关(进一步地,将指针转换为void*不需要强制转换,因为它是隐式的)。int*void**以及除了void*之外的任何其他指针都没有这个属性。


赋予void*额外自由的同时,也带来了额外的限制。void*不能被间接引用,也不能与指针算术一起使用。这些限制只可能存在,因为永远不可能有一种类型为void的对象。或者从相反的角度看,由于这些限制,void对象不能存在。

void**无法获得这些自由,因为它不能获得相同的限制。它不能获得这些限制,因为void*对象确实存在且需要存在。例如,如果我们不能对void**进行引用或迭代,那么我们就无法使用void*数组。


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...),但具有相同的含义。
回到C和C++中声明语法:
指向int的指针的声明为int (*pi);(括号是无用的,但有助于说明问题),您可以这样阅读:我声明表达式(* pi)的类型为int。您可以这样阅读函数声明:在int f(int i);中,我声明如果i的类型为int,则f(i)的类型为int
声明 void (*pi); 看起来像是一个指向 void 的指针,但是并不存在类型为 void 的对象,表达式 *pi 甚至不是良构的,它没有意义。这是类型系统中的一个特殊情况:语法表示“指向 void”,语义表示“指向某个东西”。
在 C 和 C++ 中,指针对象是一等对象,你可以取其地址并且有一个指向指针的指针等等(与 Java 不同,Java 中引用和其他基本类型不是类对象)。
因此,你可以有一个 int**int***... 指向(指向...到 int)的指针;出于同样的原因,你可以有一个 void**:声明为指向(指向 void 的指针),语义上是指向(指向某个东西的指针)。
就像不能将指向 int 的指针分配给指向 float 的指针一样,需要进行强制转换:
float *f = &i; // ill-formed

由于类型不匹配,与void **不同的类型无法分配给void **void **进行解引用的结果必须是void *对象


1
有趣的是,指针类型之间的 reinterpret_cast 实际上被定义为产生与转换为 void* 然后 static_cast 相同的结果。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接