Преобразование типа ** в void *, а затем обратно в Type*

#c #casting

#c #Кастинг

Вопрос:

У меня возникли проблемы с приведением.

Класс A имеет открытый метод: char* m()

funcA получает двойной указатель на тип A и преобразует его в указатель void. В funcB я хочу привести его обратно к типу A, чтобы я мог вызвать метод m (). Я пробовал нижеприведенное, но с треском провалился.

 void funcA(const A** a) {
    funcB((void*)a)
}

void funcB(void* b) {
    A* a = (A*) b; // 
    printf("M: %s", a->m()); // => crash!
}
  

Как я могу преобразовать указатель void обратно в тип A, чтобы я мог вызвать метод?

Комментарии:

1. Ну, A* и A** это две разные вещи.

2. const **A a Действительно ли допустимый синтаксис? Разве это не должно быть const A ** a ?

3. @rattmuff: Как бы вы вызвали метод из funcA ?

4. @unwind Так и должно быть, ошибка публикации.

5. @pts Я не понимаю, это вызывается из системы, находящейся вне моего контроля. Я управляю только funcB.

Ответ №1:

Две возможности:

 void funcA(const A** a) {
    funcB((void*)*a);   // passing an A* to funcB
}

void funcB(void* b) {
    A* a = (A*) b;
    [...]
}
  

или

 void funcA(const A** a) {
    funcB((void*)a);    // passing an A** to funcB
}

void funcB(void* b) {
    A* a = *(A**)(b);
    [...]
}
  

Обратите внимание, что тип, который мы используем для приведения b в funcB , должен соответствовать типу того, что мы передали из funcA . Это легко ошибиться, поскольку мы удаляем всю информацию о типе после приведения к void* , поэтому компилятор не может нам здесь помочь.

Также имейте в виду, что при том, как это написано сейчас, мы теряем const квалификатор в оригинале a . Это потенциально плохо. Возможно, вместо этого вы захотите привести к const A* in funcB .

Ответ №2:

Type** является указателем на Type* , в то время как Type* является указателем на объект типа Type .

Итак, если мы предположим, что funcA получает действительный указатель на указатель на объект типа A , вы должны сначала разыменовать его с помощью * оператора.

 funcB((void*) *a)
  

Вы должны видеть A** a параметр таким, какой он есть на самом деле — значением в памяти. Это значение является адресом, точнее адресом a A* . Итак, если вы разыменовываете a A** , вы получаете A* . Полученное значение снова является адресом, но самого объекта типа A .

  • A** содержит адрес к A*
  • A* содержит адрес объекта типа A

Ответ №3:

Проблема в том, что параметр a в funcA является A** , не A* . Таким образом, вы начинаете с A** и заканчиваете на A* , и адреса не имеют членов.