为什么在声明指向函数的通用指针时会出错?

Why is there an error while declaring a generic pointer to a function?

在执行此代码时,我在第 ptr = (void* (void*, void*))sumx;

行得到 [Error] cast specifies function type

我正在尝试声明一个通用指针 ptr 指向一个名为 sumx

的函数

如有任何帮助,我们将不胜感激。谢谢。

# include <stdio.h>

int sum(int a, int b) {
    return a+b;
}

int* sumx(int *a, int *b) {
    int *p;
    *p = *a+*b;
    return p;
}

int main() {
    int (*p) (int, int);
    void* (*ptr)(void*, void*);

    p = sum;
    ptr = (void* (void*, void*))sumx;


    int s = (*p)(5, 6);

    int a = 10;
    int b = 20;
    int *y = (*ptr)(&a, &b);

    printf("%d\n", s);
    printf("%d\n", *y);
    return 0;
}

您在演员表中缺少 (*),应该是这样的:

ptr = ( void* (*)(void*, void*) )sumx;

但是,在使用这样的函数指针时,一般使用typedef语句会清晰很多:

#include <stdio.h>
#include <stdlib.h>

int sum(int a, int b)
{
    return a + b;
}

int* sumx(int* a, int* b)
{
    int* p = malloc(sizeof(int)); // Need to allocate some memory
    *p = *a + *b;
    return p;
}

typedef int (*ifncptr)(int, int);
typedef void* (*vpfncptr)(void*, void*);

int main()
{
    ifncptr p;
    vpfncptr ptr;
    p = sum;
    ptr = (vpfncptr)sumx;

    int s = p(5, 6); // You can just use the fn-ptr for this call ...

    int a = 10;
    int b = 20;
    int* y = ptr(&a, &b); // ^ ... and here, also!

    printf("%d\n", s);
    printf("%d\n", *y);
    free(y); // Don't forget to free the memory.
    return 0;
}
int* sumx(int *a, int *b) {
    int *p;
    *p = *a+*b;
    return p;
}

你正在写入一个未初始化的指针,使用malloc保留space:

    int *p = malloc(sizeof(*p));

并回答您的问题:

void* (*ptr)(void*, void*);

不是 sumx 的有效签名,而是:

int *(*ptr)(int *,  int*);

Why is there an error while declaring a generic pointer to a function?

因为在 C 语言中不存在指向函数的通用指针这样的东西。 void* 是指向 对象 (变量)的通用指针。 void* 只能与对象指针一起使用,不能与函数指针一起使用。

然而,可以在一个函数指针与另一个函数指针之间进行转换,但是当您调用实际函数时,您必须通过正确的函数指针类型来执行此操作。


关于未分配内存等,您还有其他各种错误,这些错误已由其他答案解决。但是让我们忽略所有这些,以及在这种情况下并没有真正满足目的的函数指针的使用。您实际想要做的事情可以通过以下方式使用现代标准 C 实现:

#include <stdio.h>

int sum_int(int a, int b) {
  return a + b;
}

int sum_intp(const int *a, const int *b) {
  return *a + *b;
}

#define sum(a,b) ( (void)_Generic((b), int:0, int*:0),/*NOTE: comma operator*/ \
  _Generic((a),  \
  int:  sum_int, \
  int*: sum_intp)(a,b) )

int main(void) 
{
  int a=10;
  int b=20;
  printf("%d\n", sum(a, b));
  printf("%d\n", sum(&a, &b));
  //printf("%d\n", sum(a, &b)); //compiler error
  //printf("%d\n", sum((float)a, b)); //compiler error
  return 0;
}

C11 _Generic 宏在编译时确定类型。宏的伪代码是:

  • 检查参数 b 是否为有效类型。
  • 丢弃此参数的值 b 检查 - 它只是在类型错误的情况下生成编译器错误。
  • 逗号运算符。
  • "检查参数a是否也有效,然后根据a的类型调用正确的函数。

这是类型安全的,不需要 void* 或函数指针。

主要问题

实际上您不能在表达式中使用函数。当在表达式中使用函数时,它会自动转换为指向函数的指针。1

这意味着您的转换不应尝试转换为 void *(void *, void *) 之类的函数类型,而应转换为 void *(*)(void *, void *).

之类的指向函数的指针类型

两个问题

C 允许将指向函数的指针转换为不同类型的指向函数的指针,但是,当函数被调用时,用于调用的指针应遵守某些与实际函数定义兼容的规则。将参数或 return 类型从 int * 更改为 void * 不遵守这些规则。因此,对于您拥有的类型,(*ptr)(&a, &b) 不是正确的调用。

sumx中,p*p = *a + *b;之前没有被初始化,所以不能期望它指向任何东西。您应该初始化它,可能使用 p = malloc(sizeof *p);。调用 malloc 后,您应该测试结果。如果它等于 NULL,您的程序应该打印一条错误消息并退出或以其他方式处理分配内存失败。

脚注

1 这有两个例外。一种是当你用 & 手动获取一个函数的地址时,没有自动转换。另一个是当 sizeof 应用于函数时没有转换,但随后存在约束违规。 C 标准没有定义将 sizeof 应用于函数的行为。