问题
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 fromint **
tovoid **
note: Types pointed to are unrelated; conversion requiresreinterpret_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