C中的函数指针有没有*之间有区别?
像我这样的函数指针声明
typedef void (*DListVisitNode) (Node*, void*);
void DListTraverse( NodeList* , DListVisitNode , void*);
我有像这样的代码
void print_index( Node* node, void* ctx)
{
printf("index:%d\n", node->index);
}
void* print_content( Node* node, void* ctx)
{
printf("content:%s\n", node->content);
}
void DListTraverse(NodeList* nodelist, DListVisitNode visit_func, void* ctx)
{
Node* cur_node = nodelist->headnode;
while( cur_node != NULL)
{
visit_func( cur_node, ctx );
cur_node = cur_node->nextnode;
}
}
DListTraverse( nodelist, print_content, NULL );
DListTraverse( nodelist, print_index, NULL );
两个DListTraverse都可以正常工作,但带有*的那个会像这样发出警告
warning: passing argument 2 of ‘DListTraverse’ from incompatible pointer type
我之后只会删除*,但它们之间的区别是什么?
答案 0 :(得分:3)
print_content
被定义为返回void*
,即通用原始指针。
print_index
被定义为返回void
,即没有任何结果。
这些是不同的签名。只有print_index
匹配DListVisitNode
。
我的编码风格是通过typedef
来定义签名
typedef void signature_t (int);
请注意,上面没有涉及指针。这用一个int
参数命名函数的签名,但没有结果。
然后,当需要指向上述签名的此类函数的指针时,请使用signature_t*
真实的是函数的名称就像数组的名称;语言隐式地将它们转换为指针。因此DListTraverse(nodelist, print_content, NULL)
被理解为DListTraverse(nodelist, &print_content, NULL)
您应该在编译器上启用所有警告;使用gcc
表示将-Wall -Wextra
作为程序参数提供给编译器。
答案 1 :(得分:2)
您已将print_content
声明为返回void *
(指针),这意味着它与DListVisitNode
不匹配。但是,由于该函数实际上没有返回任何内容(没有返回语句),因此您应该收到另一个警告。
答案 2 :(得分:2)
您可能会对以下与typedef之间的区别感到困惑:
typedef void (*DListVisitNode) (Node*, void*);
typedef void * (*DListVisitNode) (Node*, void*);
或等效地,在以下两种类型之间:
void (*) (Node *, void *)
void * (*) (Node *, void *)
前者是指向返回void
的函数的指针,后者是指向返回void *
的函数的指针。每个打印功能都是一个这样的功能的例子。
当然,不同类型的函数指针是不兼容的,不能隐式转换,因为这肯定是没有意义的:你不能只假装一个函数实际上有一个完全不同的签名,并期望能够在任何函数中调用它。有意义的方式这就好比假装自行车是汽车,然后试图在加油站给它加油。
答案 3 :(得分:1)
typedef void (*DListVisitNode) (Node*, void*);
将指向函数的指针定义为 类型 ,它采用两个参数Node *
和void *
并返回void
。
使用上述语句后,DListVisitNode
可用作类型,具体类型如上所述。
void* print_content( Node* node, void* ctx)
返回void *
而不是void
C是强类型语言,c标准规定编译器必须报告任何类型违规,因此存在 类型不匹配 ,编译器会向您报告。基本上,如果您的函数没有返回任何内容,请使用返回类型为void
,或者如果您打算返回特定类型,则使用该特定类型作为返回类型。