Компилятор C жалуется на void (*) - PullRequest
1 голос
/ 25 января 2010

Мой профессор определил это в файле .h

void list_map(INTLIST* list, void (*f)(void *)); /*Applies a function to each element of the list */

Я написал такую ​​функцию:

 void list_map(INTLIST* list, void (*f)(void *))
  {
   INTLIST* pTemp=NULL;

   if (list == NULL)
    {
      //list is empty
    }
   else
      {
       for(pTemp=list; pTemp->next!=NULL; pTemp=pTemp->next)
          {
             f(pTemp); //f is a function pointer we call list map from main like list_map(lst, list_sort)
          }    
      }
  }

Я называю это в основном так:

  list_map(aList[i], (void*)list_sort);

В среде Windows нет претензий, но я должен запустить это в среде Linux. Я использую make-файл для компиляции всего кода, и я получаю это предупреждение и ошибку:

* c ++ -O2 -c main.c main.c: В функции «int main (int, char **)»: main.c: 53: предупреждение: устаревшее преобразование из строковой константы в 'char *' main.c: 123: ошибка: неверное преобразование из «void () (INTLIST )» в «void () (void )» main.c: 123: ошибка: инициализация аргумента 2 из «void list_map (INTLIST *, void () (void ))» make: *** [main.o] Ошибка 1 *

Может ли кто-нибудь сначала помочь с ошибкой, а затем, возможно, с предупреждением?

Редактировать часть:

Кто-то спросил функцию list_sort, вот она:

 void list_sort(INTLIST* list)
 {
  INTLIST* pTemp=NULL;
  INTLIST* pTemp2=NULL;

  pTemp=list;          //temp pointers to compare node values
  pTemp2=list;

  if (pTemp->next !=NULL)     //move to second node
   {
      pTemp2=pTemp2->next;
   }

  while(pTemp2 != NULL)
   {   
       //we implement a selection sort 
       //check if incoming node->datum with each node in the list
       //swap values if <
      if (pTemp2->datum < pTemp->datum)
         {
         //swap the values
         int temp = pTemp->datum;
         pTemp->datum = pTemp2->datum;
         pTemp2->datum = temp;
         }
         //advance the pointer
      pTemp2=pTemp2->next;
   }
 }

Ответы [ 5 ]

2 голосов
/ 25 января 2010

Простого приведения list_sort() достаточно, чтобы предупреждение исчезло, но этого недостаточно, чтобы оно действительно заработало:

Стандарт C не гарантирует, что INTLIST * иvoid * имеют совместимые представления, то есть void (INTLIST *) и void (void *) являются различными несовместимыми типами.Когда list_map() вызывает list_sort() через ваш аргумент void (*f)(void *), применяется раздел C99 6.3.2.3, §8:

Если преобразованный указатель используется для вызова функции, тип которой несовместим суказательный тип, поведение не определено.

Чтобы сделать его совместимым со стандартом, необходимо написать функцию-обертку для list_sort():

void list_sort_wrapper(void *list)
{
    list_sort(list);
}

и использовать еев качестве аргумента для вашего вызова:

list_map(aList[i], list_sort_wrapper);

Кроме того, если list_sort() реализован правильно (не проверял алгоритм), он уже просматривает список, то есть вызов его для каждого узла не приводит ксмысл вообще.

edit:

Ok, list_sort() на самом деле не сортирует весь список - это можно сделать с помощью

list_map(list, list_sort_wrapper);

Схема именования - это серьезный WTF - если функция не сортирует список, назовите его list_sort_step() или list_select_head() или что-то еще, но, пожалуйста, не list_sort().

2 голосов
/ 25 января 2010

Ну,

void list_sort(INTLIST* list)

имеет неверную подпись для передачи в качестве второго аргумента

void list_map(INTLIST* list, void (*f)(void *))
2 голосов
/ 25 января 2010

А если вы приведете свой обратный вызов к правильному типу функции?

list_map(aList[i], (void (*)(void*))list_sort);
1 голос
/ 25 января 2010

Первое: почему вы компилируете код C как C ++? . Пожалуйста, скомпилируйте его с помощью компилятора C.

Прототип list_sort():

void list_sort(INTLIST* list);

и list_map() имеет прототип:

void list_map(INTLIST* list, void (*f)(void *));

Это означает, что второй аргумент list_map() - это функция, которая принимает аргумент void * и возвращает void (ничего).

Теперь стандарт C гарантирует, что преобразование любого указателя объекта в void * и обратно в порядке, поэтому дано:

INTLIST *l;
/* make l point to a valid INTLIST */
void *pl = l;

все в порядке:

list_sort(pl);

Обратите внимание, что list_sort() мог быть объявлен как:

void list_sort_generic(void *l);

На самом деле, поскольку ваш профессор использует void * в некоторых местах, он хочет расширить ваши списки, чтобы они в какой-то момент были универсального типа.

В любом случае, вы можете передать INTLIST * в list_sort() или list_sort_generic(), но list_sort_generic() можно передать любой указатель объекта, тогда как list_sort() можно передать только INTLIST * (или void *, который был преобразован из INTLIST *).

Даже если list_sort() может принимать void *, подпись list_sort() не является

void list_sort(void *l);

Итак, типы функций list_sort() и list_sort_generic() не совпадают и не могут быть взаимозаменяемы. list_map() ожидает функцию того же типа, что и list_sort_generic(), но получает функцию другого типа.

Поскольку вы не можете менять прототипы, вам нужен состав. Теперь void * является универсальным типом в C, так что вы могли бы подумать, что такое приведение будет работать. Но, как я уже говорил, только указатели объектов могут быть преобразованы в void * и обратно - & mdash; не тип указателя на функцию. Таким образом, вам нужно привести list_sort() к правильному типу при вызове list_map().

Это правильный тип void (*)(void *). Эта функция возвращает void и принимает void *.

Следовательно, вызов должен быть:

list_map(aList[i], (void (*)(void *))list_sort);

Но, поскольку тип list_sort() и тип, ожидаемый list_map() для его второго параметра, не совпадают, приведение может работать или не работать. Ваш профессор дал вам «не очень хорошие» (то есть неправильные ) прототипы. Либо он должен был пройти весь путь в объявлении типовых функций, либо он должен был оставить все INTLIST *. Пройдя половину пути, он ввел сложный актерский состав, которого не должно было быть, и он может не работать. Я уверен, что если вы доведете это до сведения вашего профессора, он допустит этот недосмотр.

Надеюсь, это помогло.

0 голосов
/ 25 января 2010

В вашей функции list_sort, параметр INTLIST *list.

list_map(aList[i], (void*)list_sort);

Если посмотреть на заголовок, то прототип функции - это указатель на функцию с параметром типа void *

void list_map(INTLIST* list, void (*f)(void *))
                                      ^^^^^^^^

Указатель функции *f должен соответствовать сигнатуре, следовательно, конфликт и предупреждение генерируются вашим компилятором. Поскольку *f указывает на list_sort, сигнатура метода не совпадает.

Это сработало бы, если бы вместо этого у прототипа вашей функции

void list_map(INTLIST* list, void (*f)(INTLIST *))

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...