Почему я должен повторно интерпретировать указатели указателей? - PullRequest
0 голосов
/ 21 сентября 2018

Таким образом, этот код 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 голосов
/ 21 сентября 2018
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 даже не очень хорошо сформировано, оно не имеет смысла.Это особый случай в системе типов: синтаксис говорит «указатель на пустоту», семантический - «указатель на что-то».

В C и C ++ объект указателя является первым классомобъект, и вы можете взять его адрес и иметь указатель на указатель и т. д. (В отличие от Java, где ссылки, как и другие фундаментальные типы, не являются объектами класса.)

Таким образом, вы можете иметь int**, int*** ... указатели на (указатели ... на int);по той же причине вы можете иметь void**: объявлено как указатель на (указатель на пустоту), семантически указатель на (указатель на что-то).

Так же, как указатель на int не может бытьприсваивается указатель на float без приведения:

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

из-за несоответствия типов, тип, отличный от void**, не может быть присвоен void**: результатудля разыменования void** должен быть void* объект .

0 голосов
/ 21 сентября 2018

int никак не связано с void.То же самое относится к int** и void**, и поэтому они не могут быть преобразованы с использованием static_cast.

void*, однако special .Любой тип указателя данных (включая int*) может быть static_cast в void* и обратно, несмотря на то, что никакой тип не связан с void (даже более того, преобразование в void* не нуждается в приведении, так какнеявно).int* не имеет этого свойства, а также void** и других указателей, кроме void*.


Дополнительные свободы, предоставленные void*, имеют дополнительные ограничения.,void* не может быть ни косвенным, ни использоваться с арифметикой указателя.Эти ограничения возможны только потому, что никогда не может быть объекта типа void.Или с противоположной точки зрения, объекты void не могут существовать из-за этих ограничений.

void** не могут быть предоставлены эти свободы, потому что ему не могут быть даны те же ограничения.Эти ограничения не могут быть даны, потому что void* объекты существуют и они должны существовать.Если мы не могли косвенно или итерировать void**, то мы не могли бы использовать массивы void*, например.

...