首页 文章

C编译器抱怨void(*)

提问于
浏览
1

我的教授在.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环境中运行它 . 我正在使用makefile来编译所有代码,我收到此警告和错误:

  • 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:错误:初始化'void list_map的参数2(INTLIST ,void()(void))' make: [main.o]错误1 *

有人可以先帮助解决错误,然后再发出警告吗?

Edit Portion:

有人要求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 回答

  • 0

    第一:为什么要将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 * 并且可以转换为portable-not函数指针类型 . 因此,在调用 list_map() 时,需要将 list_sort() 强制转换为正确的类型 .

    正确的类型是 void (*)(void *) . 这是一个返回 void 并取 void * 的函数 .

    因此,呼叫应该是:

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

    但是,由于 list_sort() 的类型和 list_map() 期望的第二个参数的类型不相同,因此强制转换可能有效,也可能无效 . 你的教授给了你"not-so-nice"(即错误的)原型 . 要么他应该在声明类型泛型函数时一直走,要么他应该保留所有东西 INTLIST * . 通过中途,他引入了一个不应该引起注意的复杂演员阵容,他将承认这种疏忽 .

    希望有所帮助 .

  • 1

    如果你将回调转换为正确的函数类型?

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

    好,

    void list_sort(INTLIST* list)
    

    有错误的签名作为第二个参数传递

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

    一个简单的 list_sort() 演员足以使警告消失,但这还不足以让它真正起作用:

    C标准不保证 INTLIST *void * 具有兼容的表示,即 void (INTLIST *)void (void *) 是不同的,不兼容的类型 . 当 list_map() 通过 void (*f)(void *) 参数调用 list_sort() 时,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:

    好的, list_sort() 实际上并没有对整个列表进行排序 - 这可以通过实现

    list_map(list, list_sort_wrapper);
    

    命名方案是一个严重的WTF - 如果函数没有对列表进行排序,请将其命名为 list_sort_step()list_select_head() 或其他东西,但请不要 list_sort() .

  • 2

    在函数 list_sort 中,参数为 INTLIST *list .

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

    通过查看 Headers ,函数原型是一个函数指针,其参数类型为 void *

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

    函数指针 *f 必须匹配签名,因此冲突和编译器生成的警告 . 由于 *f 指向 list_sort ,因此方法签名不匹配 .

    如果您的函数原型具有此功能,它将起作用

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

    希望这会有所帮助,最好的问候,汤姆 .

相关问题