在 C 中返回函数数组

Returning array of functions in C

我正在构建一个包含大量使用相同 "main" 功能的文件的应用程序

例如:

file1 as 3 functions called: doX, doY, doZ file2 as 1 函数调用:abc file3 作为 10 个函数调用:a1、a2、a3 等...

我有一个处理这些函数的主程序,以便生成和计算正确的数据。

我遇到的问题是 "main" 程序不知道要 运行 哪些函数,所以我想为我的所有文件创建一个通用函数,它将 return 列表按特定顺序

运行 的函数

但由于某些原因它不起作用

这是我的示例代码

  // in main.h
  #include <stdio.h>

  // in file1.c
  // #include ...
  int doX() {
    // do stuff
    return 1;
  }

  int doY() {
    // do stuff
    return 1;
  }

  int * get_tasks() {

    int (*task[2])() = { };
    int id = 0;

    id++; task[id] = doX;
    id++; task[id] = doY;

    return *task;
  }

  // main.c
  #include "main.h"
  int main () {

    int * pl;
    int i, success = 0;

    printf("do stuff");
    pl = get_tasks();

    for(i = 0; i < 2; i++) {
      success += *(pl[i])();
    }

    printf("success = %d", success);

  }

当我 运行: gcc *.c

我得到:

test.c: In function ‘get_tasks’:
test.c:24:3: warning: return from incompatible pointer type [enabled by default]
   return *task;
   ^
test.c: In function ‘main’:
test.c:38:24: error: called object is not a function or function pointer
     success += *(pl[i])();
                     ^

我该如何解决这个问题?

正确的做法是

typedef int (*FunctionType)(void);

然后将函数指针声明为

FunctionType functionPointer;

你还有更多问题

  1. 不要 return 指向局部变量的指针。
  2. 你在 task[id] = ... 之前增加了 id,这也是你用一种非常混乱的风格做的,有两个问题

    1. 可以使用前置自增运算符,比如

      task[++id] = ...;
      
    2. 仍然是错误的,因为数组是0基索引,所以通过访问task[1]你实际上是在数组的末尾,task[2] 会导致未定义的行为。

这是您的代码的工作版本

#include <stdio.h>

typedef int (*FunctionType)(void);

int doX(void) {
    return 1;
}

int doY(void) {
    return 1;
}

void gettasks(FunctionType task[2])
{
    int id = 0;

    task[id++] = doX;
    task[id++] = doY;
}

int main(void) {
    FunctionType tasks[2];
    int i, success = 0;

    printf("do stuff\n");
    gettasks(tasks);

    for(i = 0; i < 2; i++) {
      success += tasks[i]();
    }
    printf("success = %d", success);
    return 0;
}

我想,通过写作

int (*task[2])() = { };
int id = 0;

id++; task[id] = doX;
id++; task[id] = doY;

您正在尝试访问索引 12,这是内存溢出并导致 undefined behaviour.

之后,task[2]get_tasks()() 的本地。您不应该返回相同的地址,因为一旦 get_tasks() 完成,task[2] 将不复存在。返回地址并在调用者中再次使用相同的地址会导致 undefined behaviour.

也就是说,在我看来,使用 typedef 作为函数指针非常方便且可读性更好。

一个函数 return 指向一个函数的指针看起来像:

int(*)()function()

而不是

int* function()

如您的代码所示。或者,您可以使用 typedef:

typedef int(*functype)();

functype function();

这让事情变得不那么混乱了。

不过,您不能 return 指向堆栈变量的指针;到您 return 时,该指针将指向无效内存。你必须使用 malloc() 或类似的东西(然后记住不要忘记清理)。或者,不要 return 指针,而是 return 结构:

struct fptrs_struct {
    int(*open)();
    int(*close)();
    // ...
}

struct fptrs_struct function() {
    struct fptrs_struct retval;
    retval.open = foo;
    retval.close = bar;
    // ...
    return retval;
}

这行得通,不需要 malloc 或类似的东西(但在 return 上涉及稍微多一点的复制)。

恭喜,您现在正在使用 C 语言进行 OO。也许为此使用一个库(提示:gobject),或者更好的是,切换到一种实际支持面向对象的语言——比如 Objective-C 或 C++.