Why do I Have to reinterpret_cast Pointer Pointers?

不羁的心 提交于 2020-01-24 10:00:06

问题


So this static_cast code is totally legal:

int n = 13;
void* pn = static_cast<void*>(&n);
void** ppn = &pn;

Yet this has to be made into a reinterpret_cast to compile:

int n = 13;
int* foo = &n;
void** bar = static_cast<void**>(&foo);

If I don't change it I get the error:

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

So I take it the issue is "the types are unrelated". Yet I still don't understand, if it's OK when going from an int* to void* how can they be unrelated as a int** and a void**?


回答1:


int is in no way related to void. The same goes for int** and void** and so they cannot be converted using static_cast.

void* however, is special. Any data pointer type (including int*) can be static_cast into void* and back, despite no type being related to void (even further, the conversion to void* doesn't need a cast, as it is implicit). int* doesn't have this property, nor does void** and nor does any other pointer besides void*.


The additional freedoms that have been granted to void* come with additional restrictions. void* cannot be indirected, nor can it be used with pointer arithmetic. These restrictions are only possible because there can never be an object of type void. Or from opposite point of view, objects of void cannot exist because of these restrictions.

void** cannot be given those freedoms, because it cannot be given the same restrictions. It cannot be given those restrictions because void* objects do exist and they need to exist. If we couldn't indirect or iterate void**, then we couldn't use arrays of void* for example.




回答2:


void* pn = static_cast<void*>(&n);

is an implicit conversion; you can also write

void *pn = &n;

It means that pn stores a pointer to some object type; the programmer is responsible for knowing what that object type is. To cast back you need a static_cast:

int *pi = static_cast<int*>(pn);

Note that using static_cast to cast to any type significantly different than the original (float is significantly different, const int isn't) is a way of doing a reinterpretation. You should spell that reinterpret_cast not implicit conversion (or static_cast) followed by static_cast.

This is the whole purpose of void*, an concept tracing back to C, where casts are spelled with C-style casts obviously (not static_cast...) but have otherwise identical meanings.

Going back to the syntax of declarations in C and C++:

The declaration of a pointer to int is int (*pi); (parentheses are useless but help illustrate the point), you can read it like: I declare that expression (*pi) has type int. You can read a function declaration that way: in int f(int i); I declare that if i has type int then f(i) has type int.

The declaration void (*pi); looks like a pointer to a void but there is no such thing as an object of type void, the expression *pi isn't even well formed, it doesn't make sense. It's a special case in the type system: the syntax says "pointer to void", semantic says "pointer to something".

In C and C++, a pointer object is a first class object and you can take its address and have a pointer to a pointer, etc. (Contrast with Java where references like other fundamental types aren't class objects.)

So you can have a int**, int***... pointers to (pointers ... to int); you can have for the same reason void**: declared like a pointer to (pointer to void), semantically a pointer to (pointer to something).

Just like a pointer to int can't be assigned to a pointer to float without a cast:

float *f = &i; // ill-formed

because of the type mismatch, a type different from void** can't be assigned to a void**: the result of dereferencing a void** must be a void* object.



来源:https://stackoverflow.com/questions/52449090/why-do-i-have-to-reinterpret-cast-pointer-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!