【问题标题】:Point to functions with different arguments using the same pointer使用相同的指针指向具有不同参数的函数
【发布时间】:2026-02-03 01:05:01
【问题描述】:

我正在尝试为给定的输入构建解析器,有 8 个可能的命令。所以我想,不要像这样使用 case switch 块的丑陋技术:

switch(command)
case cmd1:
.... /*call a function that do cmd1*/
case cmd2
..../*call a function that do cmd2*/

我将在标题中定义一个结构数组,每个结构都包含函数的名称和指向函数的指针:

typedef struct command_info
{
    char *name;
    void (*func)(int)
};
command_info command_table[] = {{"func1", &func1}, {"func2", &func2} }

这样我可以切换到更优雅的:

int i;
for(i = 0; i < COMMAND_TABLE_LENGTH; i++)
  if(!strcmp(command_table[i].name, command))
     command_table[i].func(2);

我唯一的问题是,函数有不同的参数(都返回 void)。这对我来说不是问题,因为我可以检查函数是 func1 还是 func2 搜索一个 int 参数,如果是 func3func4 搜索两个(仍然比 @ 更紧凑987654331@)。但是函数指针只指向具有特定类型和数量的参数的函数。如何制作一个可以指向任何函数的通用指针?

【问题讨论】:

  • 有一些方法可以在 C 中构建一个通用接口,但它们通常涉及 (void *) 指针,并且通常比 switch 更丑陋。做明智的事情并使用类型安全的参数为每个命令调用单独的函数。无论如何,您可能需要以不同的方式解析这些命令的参数。
  • (但如果你碰巧写了一个brainf*ck解释器,你可以将一个指向公共状态结构的指针传递给所有函数。或者使用void (*)(void)并在全局状态上操作。)
  • 标准的相关部分是 C11 §6.3.2.3 Pointers ¶8(第 6.3 节转换的一部分):_指向一种类型的函数的指针可以转换为指向另一种类型的函数的指针,然后再返回;结果应与原始指针比较。如果转换后的指针用于调用类型与引用类型不兼容的函数,则行为未定义。
  • 也许没有错,但我的印象是你太努力使你的系统模块化。模块化很好,可以帮助您轻松地维护和扩展您的程序,但它只有在模块底层有一些共同点时才有效。也许解决方案是拥有模块类:二元运算符、一元运算符和函数等。或者也许一元操作是第二个参数为空的二元操作。打印和设置值是模块系统之外的特殊操作。
  • @Some 程序员老兄回复:through generic pointers (i.e. void *)void*,一个通用的 object 指针,可能不足以编码一个 function 指针。 void* 这里没有申请,因为问题是函数指针。

标签: c pointers arguments function-pointers ansi-c


【解决方案1】:

但函数指针只指向具有特定类型和数量的参数的函数。
如何制作一个可以指向任何函数的通用指针?

在 OP 的有限情况下,使用void (*func)()


任何函数指针都可以通过类型转换转换为另一个函数指针并保留等效的函数地址。 @Jonathan Leffler

int (*foo)(int) = (int (*)(int)) sqrt;
double (*sq)(double) = (double (*)(double)) foo;
printf("%f\n", sq(2));  // prints 1.414214

函数指针不需要提供函数参数签名。

// No parameter info
//        vv     
int (*foo)() = (int (*)()) sqrt;

OP 有“函数有不同的参数(都返回 void)”,所以在 OP 的情况下代码可以使用有限的通用函数指针 void (*func)() 并失去参数检查。

typedef struct {
  char *name;      // suggest const char *name
  void (*func)();  // no parameter info nor checking
} command_info;

char buf[100];
// void setbuf(FILE * restrict stream, char * restrict buf);
command_info fred = { "my_setbuf", setbuf };

// Both compile, 2nd is UB.
fred.func(stdin, buf);  // No parameter checking.
fred.func(0);           // No parameter checking.

代码在调用.funf() 时还会引发一个微妙的问题:排名低于int/unsigned 的参数以及float 参数在传递给函数之前会被提升。最好确定参数不是char, float, short, _Bool 等以避免兼容签名问题。


void * 是一个通用的object 指针。对 function 指针进行编码可能是不够的。所以它不是一个便携式的候选人。函数指针的大小比sizeof(void*) 宽的情况并不少见。

【讨论】:

    最近更新 更多