Приведение указателей-указателей в C

Я читал о распределении распределений в C (c11) и удивляюсь, что меняется, когда он становится указателем-указателем

Скажи у меня есть функция

void** foo( someInput )

который выделяет и создает один из множества типов pre-typedef'd. Почему;

MyStructA **mystructa = foo(...);

привести к предупреждению компилятора Incompatible pointer types passing ... to type void**

Это заставляет меня использовать распределение, которое, как правило, осуждается с помощью однонаправленных указателей.
MyStructA **mystructa = (MyStructA**) foo(...someInput..);
MyStructB **mystructb = (MyStructB**) foo(...someOtherInput...);

Просто искал немного понимания от сообщества, и не видел никаких предыдущих обсуждений по этому вопросу.

2 ответа

Решение

В C указатель на пустоту может быть преобразован в указатель или из указателя на любой тип объекта без приведения. Обратите внимание, однако, что void ** не является указателем на пустоту. Это указатель на void *, Следовательно, преобразование его в другой указатель на указатель на объект, такой как MyStructA ** требует явного приведения.

Правильное решение - изменить тип возвращаемого значения foo в void *

void *foo( someInput )

Тогда возвращаемое значение foo можно использовать без приведения, например

MyStructA **mystructa = foo(...);

Вот полный пример

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
}
MyStructA;

void *foo( int a, int b, int count )
{
    int i;
    MyStructA **array = malloc( count * sizeof(MyStructA *) );
    for ( i = 0; i < count; i++ )
    {
        array[i] = malloc( sizeof(MyStructA) );
        array[i]->a = a + i;
        array[i]->b = b + i;
    }

    return( array );
}

int main( void )
{
    int i;
    int count = 4;
    MyStructA **array = foo( 5, 21, count );
    for ( i = 0; i < count; i++ )
        printf( "%d %d %d\n", i, array[i]->a, array[i]->b );
    /* freeing memory is left as an exercise for the reader */
    return 0;
}

Пустые указатели являются общими указателями. Чтобы их можно было правильно обработать, нужно выполнить соответствующую настройку типов.

Например, в функции сравнения для qsort ожидается именно такое поведение. И это общее явление, и это то, что вы должны делать (вопреки тому, что вы подразумеваете как что-то осуждаемое).

По сути, используются пустые указатели, когда можно использовать один и тот же код для разных структур данных. Однако, чтобы структуры данных можно было обрабатывать правильно, компилятору необходимо знать, как интерпретировать данные, что делается путем приведения типов.

Далее, что касается вашего заявления, я бы ожидал увидеть код формы:

MyStructA **mystructa = (MyStructA **) foo( ... );
Другие вопросы по тегам