Возврат структуры *, хранящейся в очереди fifo как void * (возврат несколькими функциями)

Привет, у меня есть небольшая проблема с void *, используемым для того, чтобы сделать код более общим. Я написал очередь fifo (используя связанный список внизу), в которой хранятся любые данные, которые можно преобразовать в void * (т.е. struct * as void *).

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

Все функции, такие как back(), unwrap'_data_from_node'() и fifo_dequeue(), возвращают эти данные как void *. Что более странно, так это то, что void * может быть приведен к struct * в fifo_dequeue(), и он будет содержать все поля, заполненные данными, в то время как при возврате из fifo_dequeue() тот же возвращаемый указатель имеет только одно заполненное поле (1-е поле), и два пустые, ноль.

   void *fifo_dequeue(fifo_queue_t *fifo, size_t *data_size) {

    doubly_linked_node_t *node;
    size_t tmp_size;
    void *tmp_data;
    void *data;

    // get data and its size from the last node in the queue
    if((node = back(fifo->queue)) == NULL) {
        fprintf(stderr, "back: queue is empty!\n");
        data_size = NULL;
        return NULL;
    };
    tmp_data = unwrap_data(node, &tmp_size);

    /** HERE I tested casting data to struct test_t and it works properly **/
    task_t *task;
    task = (task_t *) tmp_data;
    int task_size = sizeof(task);

    // copy retrieved data
    data = malloc(tmp_size);
    memcpy(data, tmp_data, tmp_size);

    // remove the last node in the queue
    //pop_back(fifo->queue);

    if(data_size != NULL) *data_size = tmp_size; // return size of data through pointer argument
    return data; /** OUTSIDE this pointer casted to struct task_t has empty fields **/
}

Базовый метод удаления узла из связанного списка при выполнении pop_back();

   void remove_node(doubly_linked_list_t *list, doubly_linked_node_t *old_node) {

    // if node to delete unspecified return error
    if (old_node == NULL) {
        fprintf(stderr, "Node to delete is empty!");
        return;
    }

    // if node to delete is the only left on the list make empty list
    if (old_node->next == old_node) // or old_node->prev = old_node
    {
        list->head = list->tail = NULL;
    } else {
        old_node->prev->next = old_node->next;
        old_node->next->prev = old_node->prev;

        if(old_node == list->head) list->head = old_node->next;
        if(old_node == list->tail) list->tail = old_node->prev;
    }

    free(old_node->data); old_node->data = NULL;
    free(old_node); old_node = NULL;
}

person Michał Ziobro    schedule 02.08.2016    source источник
comment
Я предполагаю, что проблема с memcpy заключается в том, что он копирует только указатель на структуру, хранящуюся в данных, а не содержит указатели на поля. Таким образом, первый элемент можно сохранить, но остальные будут потеряны. Мне нужно скопировать, поскольку pop_back удаляет и освобождает данные из узла в связанном списке   -  person Michał Ziobro    schedule 02.08.2016
comment
int task_size = sizeof(task) ‹-- это не может быть правильным: sizeof *task я думаю, что вы хотите, и во всяком случае: sizeof возвращает size_t, а не int. Также task_t *task; task = (task_t *) tmp_data; выглядит некрасиво. Почему бы и нет task_t * task = tmp_data;. Актерский состав не нужен. Это чистый, легко читаемый однострочник   -  person Elias Van Ootegem    schedule 02.08.2016
comment
Да, но это task_t — всего лишь тестовый код. Я размещаю его, чтобы показать, что, когда он приведен к реальному типу task_t * (структуры), все поля заполнены, но когда я просто работаю с void * (общий тип) и копирую его, а затем возвращаю как void *, тогда я проигрыш полей, даже если позже тому же составу. Я думаю, что это эффект memcpy void *, а не настоящий тип. Но я не знаю, как компенсировать эту проблему. Я не хочу терять дженерики в моей нижней очереди fifo и связанном списке, а также не хочу создавать беспорядок, передавая дополнительные типы литейщиков, чтобы сделать эту копию безопасной для типов.   -  person Michał Ziobro    schedule 05.08.2016


Ответы (1)


Проблема с sizeof()

Вы берете только размер указателя в этой строке

int task_size = sizeof(task);

после этого копируется недостаточно данных.

Вам нужно malloc и скопировать всю структуру по размеру структуры:

int task_size = sizeof(task_t);
person eyalm    schedule 02.08.2016
comment
да, но данные, хранящиеся в связанном списке в fifo_queue, являются указателями (void * data) - person Michał Ziobro; 02.08.2016
comment
если вы хотите только вернуть указатель, продолжайте. Не нужно ничего копировать. Но если вы хотите скопировать всю структуру, вам нужно скопировать размер структуры. - person eyalm; 02.08.2016
comment
да, но проблема в том, что я хочу вернуть void * из fifo_dequeue(), чтобы очередь fifo могла хранить общие типизированные данные и использоваться повторно. Я мог бы вернуть только этот указатель tmp_data, а не mamcpy(), но есть еще одна проблема, поскольку раньше есть pop_back(), который удаляет узел из fifo_queue (связанный список), а затем освобождает() этот указатель, поэтому я хочу сделать копию Это. Может быть, мне следует удалить это освобождение данных - person Michał Ziobro; 02.08.2016
comment
Я думаю, что удаление этого удаления данных при извлечении узла из списка будет лучшим решением, позволяющим сохранить все структуры данных универсальными. Я думаю, мне нужно будет освободить данные позже. Но также есть сомнения, что, если кто-то будет просто pop_back() без получения данных в таком связанном списке, и эти данные никогда не будут освобождены - person Michał Ziobro; 02.08.2016
comment
если вы не хотите, чтобы очередь знала что-либо о полезной нагрузке. Вы должны добавить возможность зарегистрировать бесплатную функцию (диструктор) для каждого узла. Подумайте о ситуации, когда memcpy недостаточно. Вам может понадобиться строка в структуре, - person eyalm; 02.08.2016