3

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

我会简单地删除 * 之后,但它们之间有什么区别?

4

4 回答 4

3

print_content被定义为返回一个void*即通用的原始指针。

print_index被定义为返回voidie 没有任何结果。

这些是不同的签名。只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给编译器。

于 2012-09-07T06:17:08.280 回答
2

您可能对以下与 typedef 的区别感到困惑:

typedef void (*DListVisitNode) (Node*, void*);
typedef void * (*DListVisitNode) (Node*, void*);

或者等效地,介于以下两种类型之间:

  • void (*) (Node *, void *)

  • void * (*) (Node *, void *)

前者是指向函数返回void的指针,后者是指向函数返回的指针void *。您的每个打印功能都是此类功能的一个示例。

自然,不同类型的函数指针是不兼容的,也不能隐式转换,这肯定是没有意义的:你不能假装一个函数实际上具有完全不同的签名,并期望能够以任何有意义的方式调用它。这就像假装自行车是一辆汽车,然后试图在加油站给它加油。

于 2012-09-07T06:24:35.883 回答
2

您已声明print_content返回一个void *(指针),这意味着它不匹配DListVisitNode。但是,由于该函数实际上并没有返回任何内容(没有返回语句),因此您应该对此发出另一个警告。

于 2012-09-07T06:17:42.873 回答
1
typedef void (*DListVisitNode) (Node*, void*);     

将指向函数的指针定义为接受两个参数并返回 a的类型。 一旦你使用了上面的语句,就可以作为一个类型使用,确切的类型如上所述。 Node *void *void
DListVisitNode

void* print_content( Node* node, void* ctx) 

返回 avoid *而不是 a void
C 是一种强类型语言,c 标准要求编译器必须报告任何类型违规,因此存在类型不匹配,编译器会将其报告给您。基本上,如果您的函数不返回任何内容,请使用返回类型,void或者如果您打算返回特定类型,则使用该特定类型作为返回类型。

于 2012-09-07T06:17:54.913 回答