Приведение из void * в структуру

avatar
user1889966
16 марта 2013 в 19:18
12783
3
7

Я передаю данные типа struct Person в связанный список, поэтому указатель данных каждого узла указывает на структуру Person.

struct Person {
char name[16];
char text[24];
};

Я пытаюсь пройти по списку и распечатать имя / текст в каждом узле, вызывая

traverse(&list, &print);

Прототип траверса:

void traverseList(struct List *list, void (*f)(void *));   

Список определяется как:

struct List {
struct Node *head;
};

Моя функция печати принимает данные void *:

print(void *data) { .... }

Я знаю, что мне нужно преобразовать данные в структуру Person, верно?

struct Person *person = (struct Person *)data;
printf("%s", person->name);

Я знаю, что этого недостаточно, так как я получаю предупреждение «Инициализация из-за несовместимого типа указателя». Как я могу успешно использовать void * в этом случае? Спасибо.

Источник
Valeri Atamaniouk
16 марта 2013 в 19:22
0

Что такое прототип traverse? А какой тип list?

unxnut
16 марта 2013 в 19:25
0

Вы можете проверить, как вы передаете список для обхода и как вы на самом деле используете print. Кажется, все, что вы показали, совпадает.

user1889966
16 марта 2013 в 19:29
0

@ValeriAtamaniouk Я отредактировал свой вопрос, чтобы включить их.

Valeri Atamaniouk
16 марта 2013 в 19:34
0

@ user1889966 - ваш print объявлен как есть или возвращает void? Если он заявлен без возврата, вероятно, это int

user1889966
16 марта 2013 в 19:38
0

@ValeriAtamaniouk Прошу прощения за то, что не включил это, он объявлен как static void.

Daniel Fischer
16 марта 2013 в 19:47
0

«инициализация из несовместимого типа указателя» не имеет смысла для строки struct Person *person = (struct Person *)data;, поскольку а) void* совместим со всеми типами указателя на объект, б) вы явно приводите.

Valeri Atamaniouk
16 марта 2013 в 19:48
0

@ user1889966 Код кажется правильным для C. Вам нужно добавить дополнительный код из traverse и print

Owen S.
16 марта 2013 в 20:12
0

См. В моем ответе ссылку на рабочий пример, включающий имеющийся у вас код.

Ответы (3)

avatar
Owen S.
16 марта 2013 в 19:46
3

Проблема не в приведении типов и даже не в том, как вы передаете функцию. Проблема в том, что в вашем объявлении print отсутствует тип возврата, и в этом случае обычно предполагается int. Компилятор жалуется, потому что вы передаете int (*)(void*) функции, которая ожидает void (*)(void*).

Это легко исправить: просто добавьте void перед объявлением функции print. См.:

https://gist.github.com/ods94065/5178095

avatar
Chris
16 марта 2013 в 19:42
0

Ваша функция traverseList принимает указатель на функцию (который принимает указатель void), но не принимает аргумент для этих пустых данных. Кажется, это то, что вам нужно:

void print (void* data)
{
    printf("%s", ((struct Person*)data)->name);
}

void traverseList (struct List *list, void(*f)(void*), void* data)
{
    f(data);
}

Затем вы можете вызвать traverseList:

traverseList (&list, &print, &person);
Daniel Fischer
16 марта 2013 в 19:45
0

Я бы подумал, что аргумент, который traverse предоставляет для print, является элементом data аргумента struct List * аргумента traverse соответственно. более поздние узлы в списке.

avatar
Leo Chapiro
16 марта 2013 в 19:22
1

Моя функция печати принимает данные void *

Я бы сказал, перепишите вашу функцию print, приняв struct Person *.

Valeri Atamaniouk
16 марта 2013 в 19:53
0

Какое это имеет значение? В C void* совместим с любым неконстантным указателем на структуру.

Leo Chapiro
16 марта 2013 в 19:56
0

Просто потому, что забрасывать потом не надо.

Owen S.
16 марта 2013 в 20:20
0

Вам все равно потребуется приведение - вам нужно будет выполнить приведение от void (*)(struct Person*) к void (*)(void*) при передаче функции в traverse. Я подозреваю, что это менее безопасно, и IMO менее элегантно.