Передача структуры в универсальную функцию на C

#c

#c

Вопрос:

Я объявляю новую структуру с именем «Struct», у меня есть универсальная функция, которая принимает в качестве аргумента «void *data».

 void Foo(void *data)
  

Я передаю экземпляр «Struct» в универсальную функцию.

 Struct s;
Foo(amp;s);
  

Я хочу получить доступ к одному из свойств структуры в функции.

 void Foo(void *data) {
    char *word = (char*) data.word;
}
  

Это недопустимо, поскольку оно не распознает данные как допустимую структуру.

Я даже пытаюсь сначала объявить данные как тип struct, и я получаю ошибку.

 void Foo(void *data) {
    Struct s = (Struct) data;
    char *word = s.word;
}
  

Я получаю «запрошено преобразование в нескалярный тип».

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

1. Если вам нужно, чтобы это была структура, зачем вообще передавать void*?!

2. @Bo: Функция может быть функцией обратного вызова, которая должна соответствовать внешне определяемому API, вызывающий объект и функция будут знать, что должно быть в void *data но промежуточный код может и не знать. Смотрите bsearch и qsort примеры из стандартной библиотеки.

Ответ №1:

Прежде всего, вы должны включить предупреждающие флаги вашего компилятора (все из них). Затем вы должны передать указатель на свой Struct и использовать что-то другое, чем struct , в качестве имени переменной:

 Struct s;
Foo(amp;s);
  

Затем в Foo :

 void Foo(void *data) {
    Struct *s    = data;
    char   *word = s->word;
}
  

Вы не можете преобразовать типы без указателей в и из void* , как вы пытаетесь, преобразование типов указателей в и из void* , с другой стороны, допустимо.

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

1. все из них? Это немного чересчур … например, в gcc опция -Wwrite-strings делает gcc компилятором для языка, похожего на, но не совсем, C 🙂

2. @pmg: Все из них (и -Werror тоже!), пока вы не сможете четко объяснить, какие из них можно удалить и почему 🙂 Когда вы сможете перехватить этот предупреждающий переключатель из hand Grasshopper, вы будете готовы.

3. Я только что подсчитал -W параметры в моем самом требовательном псевдониме gcc: 58 из них (возможно, я допустил одну или две ошибки в подсчете) … включая, -Werror но не -Wwrite-strings 😀

Ответ №2:

Вам нужно передать указатель на свою структуру и получить указатель на структуру внутри функции:

 Struct struct;
Foo(amp;struct);

void Foo(void *data) {
    Struct* struct = (Struct*) data;
    char *word = struct->word;
}
  

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

1. Кроме того, используйте struct Struct struct .

2. Приведение к (Struct*) не требуется. Некоторым людям нравится включать ее, но я считаю, что лучше этого не делать, потому что это предотвращает предупреждение компилятора, если вы попытаетесь присвоить локальной переменной указатель, не содержащий void.

3. О, и еще: struct это зарезервированное слово — выберите другое имя для локальной переменной. @Radek: Нет, если Struct это имя typedef.

Ответ №3:

Вы должны использовать -> оператор при запросе элемента структуры через указатель.

Это должно сработать: char *word = (char*) data->word;

Вы также должны передать адрес структуры функции. Вот так: Foo(amp;struct); .

Ответ №4:

Во-первых, вам нужно правильно вызвать функцию:

 Struct s;
Foo(amp;s);
  

Обратите внимание, что теперь вы передаете указатель на структуру.

Теперь функция должна знать, что вы используете Struct (в отличие от чего-то другого) — возможно, из-за другого параметра, или глобальной переменной, или по какой-то другой причине. Затем внутри функции вы можете сделать:

 void Foo(void *data) {
    Struct *structpointer = p; /* Note - no need for a cast here */


    /* (determine whether data does refer to a pointer then...) */
    char *word = structpointer->word;
    /* ... then use 'word'... */
}
  

Ответ №5:

Данные — это указатель, поэтому все, к чему вы их приводите, также должно быть указателем. Если бы вы сказали Struct* myStruct = (Struct*) data , все было бы хорошо в мире.

Ответ №6:

Вы смешиваете указатели и данные.

Struct struct определяет объект данных
void *data ожидается, что data это будет указатель.

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

Ответ №7:

 Struct struct;
Foo((void*)amp;struct);

void Foo(void *data) {
    Struct *struct = (Struct*)data;
    char *word = struct->word;
}
  

или в более компактной форме:

 Struct struct;
Foo((void*)amp;struct);

void Foo(void *data) {
    char *word = ((Struct*)data)->word;        
}