Возврат указателя на структуру из функции - PullRequest
0 голосов
/ 04 декабря 2018

Я использую некоторую библиотеку, которая объявляет некоторые непрозрачные типы.Я обернул этот тип в свою собственную структуру, чтобы абстрагироваться от непрозрачного типа этой библиотеки, и получил некоторую проблему.Вот код:

typedef struct my_struct my_struct;
struct my_struct{
    opaque_lib_t *const opaque_lib_ptr; //opaque_lib_t is the opaque type
                                        //came from the library
};

my_struct* initialize(){
    opaque_lib_t *opaque_lib_ptr;
    init(&opaque_lib_ptr);              //library function call
    return opaque_lib_ptr;
}

void use_and_release(my_struct *my_struct_ptr){
     //use and release my_struct
}

my_struct *my_struct_ptr =  initialize();
use_and_release(my_struct_ptr);         //crashes

В такой реализации происходит сбой при вызове use_and_release.Поэтому я попытался заменить my_struct* initialize на следующую реализацию

my_struct* initialize(){
     opaque_lib_t *opaque_lib_ptr;
     init(&opaque_lib_ptr);
     my_struct *my_struct_ptr = malloc(sizeof(*my_struct_ptr));
     my_struct tmp = {.opaque_lib_ptr = opaque_lib_ptr};
     memcpy(my_struct_ptr, &tmp, sizeof(tmp));
     return my_struct_ptr;
}

. С такой реализацией все работает нормально.Но я не понимаю, почему первый не сработал.Я думал, что указатель на структуру и указатель на ее первый элемент имеют одинаковое значение.Так что в этом случае было бы хорошо просто вернуть opaque_lib_t* и привести его к my_struct*, поскольку my_struct* содержит только один элемент.

1 Ответ

0 голосов
/ 04 декабря 2018

То, что вы пытаетесь сделать с первым примером, - это попытка эмулировать наследование от объектно-ориентированных языков.Похоже, вы хотите, чтобы my_struct имел отношения «есть» с opaque_lib_t.

Однако это не сработает, потому что тогда вам нужно, чтобы первый член my_struct был действительным экземпляр структуры opaque_lib_t, т.е. это должно быть

struct my_struct{
    opaque_lib_t opaque_lib_instance;   //opaque_lib_t is the opaque type
                                        //came from the library
};

Если opaque_lib_t действительно является анонимной и непрозрачной структурой, похожей на FILE, то это невозможно.

Другой взгляд на это выглядит так:

В памяти my_struct будет выглядеть примерно так:

my_struct             opaque_lib_t
+----------------+    +-------------------+
| opaque_lib_ptr | -> | Unknown data      |
+----------------+    | More unknown data |
                      | ...               |
                      +-------------------+

Вы просто не можете наложить opaque_lib_t поверх my_struct.

И когда вы делаете return opaque_lib_ptr;, вы фактически говорите, что «этот указатель указывает на my_struct, первый член которого является указателем на opaque_lib_t».И это просто неправильно, потому что это две совершенно разные структуры.

Если продолжить с первого куска кода, если вы попытаетесь использовать my_struct_ptr->opaque_lib_ptr, то память, к которой вы обращаетесь, является начальными данными структуры opaque_lib_t.(чей указатель вы вернули).


И наконец о том, что вы говорите

В моем коде я хочу абстрагироваться от конкретных структур библиотеки

Я могу это понять, но это уже цель opaque_lib_t.Вы добавляете (ненужную) абстракцию поверх абстракции.

Я мог бы понять вашу структуру, если бы она собирала несколько связанных данных, но не только указатель opaque_lib_t.

...