如何在C语言中定义一个函数数组

32
我有一个结构体包含如下声明:

I have a struct that contains a declaration like this one:

void (*functions[256])(void) //Array of 256 functions without arguments and return value

还有一个函数我想要定义它,但是有256个函数!我可以做这样的事情:

struct.functions[0] = function0;
struct.functions[1] = function1;
struct.functions[2] = function2;

诸如此类的操作太过繁琐,我想问一下有没有类似这样做的方法?

struct.functions = { function0, function1, function2, function3, ..., };

编辑:如 Chris Lutz 所说,语法错误已经被更正。

6个回答

31

我有一个包含类似这个声明的结构体:

不,你没有。那是语法错误。你要找的是:

void (*functions[256])();

这是一个函数指针数组。需要注意的是,void func()并不是"不带参数且不返回值的函数",它实际上是一种接受未指定数量或类型的参数并返回空的函数。如果你需要"不带参数",你需要使用以下方式:

void (*functions[256])(void);

C++中,void func()确实意味着“不带参数”,这会导致一些混淆(特别是因为C指定的void func()的功能具有可疑价值)。

无论如何,你应该对函数指针进行typedef。这将使代码更易于理解,并且你只有一次机会(在typedef处)出现语法错误:

typedef void (*func_type)(void);
// ...
func_type functions[256];

无论如何,你不能对数组进行赋值,但是你可以初始化一个数组并复制数据:

static func_type functions[256] = { /* initializer */ };
memcpy(mystruct.functions, functions, sizeof(functions));

请注意,memcpy() 是危险且不可移植的,因为结构体可能包含任意数量的填充字节。如果您像这里所示使用 memcpy(),则必须验证编译器未启用填充。通常通过 assert(sizeof(the_struct.functions) == sizeof(functions)) 或类似方式实现。 - Lundin
6
这是错误的。sizeof(some_struct)返回结构体的大小+任何必要的填充。例如,请参见这个问题。上面使用memcpy是正确的。 - Mat
4
在这种情况下,“memcpy()”并没有被用于结构体上,而是被用于从一个数组复制到另一个相同大小的数组,这是可以的。目标数组是结构体成员这一事实并不重要。 - caf
我可能应该注意到struct是一个关键字,因此即使是用于永远不会接近编译器的示例代码,将其用作变量名也是错误的。 - Chris Lutz
func()func(void)之间的区别只是C++的问题,而不是C的问题,对吗? - dhein

18

我有同样的问题,这是我编写的一个小程序来测试解决方案。看起来非常简单,所以我想分享给未来的访问者。

#include <stdio.h>

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

int minus(int a, int b) {
    return a-b;
}

int multiply(int a, int b) {
    return a*b;
}

typedef int (*f)(int, int);                 //declare typdef

f func[3] = {&add, &minus, &multiply};      //make array func of type f,
                                            //the pointer to a function
int main() {
    int i;
    for (i = 0; i < 3; ++i) printf("%d\n", func[i](5, 4));
    return 0;
}

3
你可以动态地进行操作...这里有一个使用malloc分配的动态函数数组的小例子...
#include <stdio.h>
#include <stdlib.h>

typedef void (*FOO_FUNC)(int x);

void a(int x)
{
    printf("Function a: %d\n", x);
}

void b(int x)
{
    printf("Function b: %d\n", x);
}

int main(int argc, char **argv)
{
    FOO_FUNC *pFoo = (FOO_FUNC *)malloc(sizeof(FOO_FUNC) * 2);
    pFoo[0] = &a;
    pFoo[1] = &b;

    pFoo[0](10);
    pFoo[1](20);

    return 0;
}

我的错...这个讨论的上下文不对...相反,你可以使用typedef来定义FOO_FUNC类型,然后创建一个FOO_FUNC数组并使用名称作为初始化程序... - TurtleToes

1

这只是我凭记忆和未经测试的想法。

// create array of pointers to functions
void (*functions[256])(void) = {&function0, &function1, &function2, ..., };

// copy pointers to struct
int i;
for (i = 0; i < 256; i++) struct.functions[i] = functions[i];

编辑:按照Chris Lutz的建议,纠正了语法错误。


0
你可以在声明结构体实例时这样做:
function_structur fs = { struct_field1,
                         struct_field2,
                         {function0, function1, ..., function255},
                         struct_field3,
                         ... };

在数组声明后,您不能使用此快捷方式来初始化数组:如果需要这样做,您将不得不动态地执行它(使用循环、memcpy或其他方法)。


0
如果你想使用类似于{func1, func2, ...}的形式对数组进行后初始化,可以通过以下方式来实现(在使用GCC编译器时): 更新(感谢Chris Lutz的评论)
定义一个宏,如下所示:
#define FUNCTION_VECTOR_COPY(destVec, sourceVec) memcpy(destVec, sourceVec, sizeof(sourceVec))

并使用复合字面常量传递源向量,如下:

#include <string.h>
...
void (*functions[256])();
...
FUNCTION_VECTOR_COPY (functions, ((void(*[])()) {func1, func2, func3}));

1
sizeof(funcsFrom)在此处无效。函数参数中的数组会衰减为指针,因此您的函数实际上是void setFuncs(void(**funcsTo)(), void(**funcsFrom)()),没有关于sizeof的信息。您应该a)使用宏,这将允许您这样做,或者b)将数组大小作为第三个参数传递。如果您选择b,则甚至可以c)编写一个包装器宏,根据第二个参数的sizeof自动插入第三个参数。此外,d)如果类型发生更改,请使用sizeof(funcsFrom) / sizeof(funcsFrom[0]),e)否则您的函数与memcpy完全相同。 - Chris Lutz
@Chris 感谢您的重要评论,我只测试了2个值,所以错过了 sizeof 问题。(a) - 太好了!; (d) - 好的,但是您应该首先检查源向量的大小是否大于0; (e) - 是的,但是您不应该忘记包含 string.h。请参见更新后的答案。 - Martin Babacaev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接