我的教授在.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 回答
第一:为什么要将C代码编译为C?请用C编译器编译它 .
list_sort()
的原型是:和
list_map()
有原型:这意味着
list_map()
的第二个参数是一个带有void *
参数的函数,并返回void
(无) .现在,C标准保证将任何对象指针转换为
void *
并返回正常,因此给出:还行吧:
请注意,
list_sort()
可能已被声明为:事实上,由于你的教授在某些地方使用
void *
,他希望在某些时候将你的列表扩展为通用类型 .无论如何,您可以将
INTLIST *
传递给list_sort()
或list_sort_generic()
,但list_sort_generic()
可以传递任何对象指针,而list_sort()
只能传递INTLIST *
(或void *
,它是从INTLIST *
转换而来的) .即使
list_sort()
可以采用void *
,list_sort()
的签名也不是:因此,
list_sort()
和list_sort_generic()
的函数类型不相同,不能互换 .list_map()
需要一个list_sort_generic()
类型的函数,但它正在获得另一种函数 .由于您无法更改任何原型,因此需要进行强制转换 . 现在,
void *
是C中的泛型类型,所以你会认为这样的演员会起作用 . 但是,正如我之前所说的,只有对象指针可以转换为void *
并且可以转换为portable-not函数指针类型 . 因此,在调用list_map()
时,需要将list_sort()
强制转换为正确的类型 .正确的类型是
void (*)(void *)
. 这是一个返回void
并取void *
的函数 .因此,呼叫应该是:
但是,由于
list_sort()
的类型和list_map()
期望的第二个参数的类型不相同,因此强制转换可能有效,也可能无效 . 你的教授给了你"not-so-nice"(即错误的)原型 . 要么他应该在声明类型泛型函数时一直走,要么他应该保留所有东西INTLIST *
. 通过中途,他引入了一个不应该引起注意的复杂演员阵容,他将承认这种疏忽 .希望有所帮助 .
如果你将回调转换为正确的函数类型?
好,
有错误的签名作为第二个参数传递
一个简单的
list_sort()
演员足以使警告消失,但这还不足以让它真正起作用:C标准不保证
INTLIST *
和void *
具有兼容的表示,即void (INTLIST *)
和void (void *)
是不同的,不兼容的类型 . 当list_map()
通过void (*f)(void *)
参数调用list_sort()
时,C99第6.3.2.3节,§8适用:要使其符合标准,您必须为
list_sort()
编写包装函数:并将其用作您的通话的参数:
此外,如果正确实施
list_sort()
(根本没有任何意义) .edit:
好的,
list_sort()
实际上并没有对整个列表进行排序 - 这可以通过实现命名方案是一个严重的WTF - 如果函数没有对列表进行排序,请将其命名为
list_sort_step()
或list_select_head()
或其他东西,但请不要list_sort()
.在函数
list_sort
中,参数为INTLIST *list
.通过查看 Headers ,函数原型是一个函数指针,其参数类型为
void *
函数指针
*f
必须匹配签名,因此冲突和编译器生成的警告 . 由于*f
指向list_sort
,因此方法签名不匹配 .如果您的函数原型具有此功能,它将起作用
希望这会有所帮助,最好的问候,汤姆 .