C语言中的函数数组
我正在从事一个项目,在这个项目中,我必须为几个函数实现一个处理程序,所有这些函数都有一个与之相关的数字。它们关联的数字是不同函数的调用方式。知道了这一点,我希望能够使用数字作为函数的索引将它们分组到一个数组中。问题是,数组内部需要有相同类型的元素,对吗?那么如何将这些函数放入数组中呢 以下是函数的编号方式:C语言中的函数数组,c,data-structures,function-pointers,C,Data Structures,Function Pointers,我正在从事一个项目,在这个项目中,我必须为几个函数实现一个处理程序,所有这些函数都有一个与之相关的数字。它们关联的数字是不同函数的调用方式。知道了这一点,我希望能够使用数字作为函数的索引将它们分组到一个数组中。问题是,数组内部需要有相同类型的元素,对吗?那么如何将这些函数放入数组中呢 以下是函数的编号方式: enum { SYS_HALT, /* Halt the operating system. */ SYS_EXIT,
enum
{
SYS_HALT, /* Halt the operating system. */
SYS_EXIT, /* Terminate this process. */
SYS_EXEC, /* Start another process. */
SYS_WAIT, /* Wait for a child process to die. */
SYS_CREATE, /* Create a file. */
SYS_REMOVE, /* Delete a file. */
SYS_OPEN, /* Open a file. */
SYS_FILESIZE, /* Obtain a file's size. */
SYS_READ, /* Read from a file. */
SYS_WRITE, /* Write to a file. */
SYS_SEEK, /* Change position in a file. */
SYS_TELL, /* Report current position in a file. */
SYS_CLOSE, /* Close a file. */
};
下面是功能原型列表:
void halt (void) NO_RETURN;
void exit (int status) NO_RETURN;
pid_t exec (const char *file);
int wait (pid_t);
bool create (const char *file, unsigned initial_size);
bool remove (const char *file);
int open (const char *file);
int filesize (int fd);
int read (int fd, void *buffer, unsigned length);
int write (int fd, const void *buffer, unsigned length);
void seek (int fd, unsigned position);
unsigned tell (int fd);
void close (int fd);
主要问题
在C语言中,有没有一种简单的方法可以将所有函数放入数组或其他数据结构中
任何帮助都将不胜感激,这是一个学校项目,所以一个小例子或链接将非常有用,但我想自己创建解决方案
谢谢
编辑:我希望能够做什么
我希望能够定义一些数组,并在枚举序号的索引处存储指向函数的指针
//I don't know how to handle the type here
<some_type> system_call_arr[128];
system_call_arr[SYS_HALT] = halt;
system_call_arr[SYS_EXIT] = exit;
system_call_arr[SYS_EXEC] = exec;
// and so on....
这是一种很好的做法吗?UNIX实现这一点的经典方法是为所有这些函数提供相同的签名(比如
int sys\u func(struct args*a)
然后将它们全部放入函数数组中。当您封送调用的参数时,只需将它们作为arg1
、arg2
等放入struct args
中,并且每个系统调用都使用不同的参数。或者,您可以在其上别名一个特殊的结构,以赋予它们有意义的名称
在您的编辑中,您会问:“这是一种好的做法吗?”我在您的问题中给出了我的答案,这似乎是一个简单操作系统内核的实现。操作系统会以正常应用程序永远不会采用的方式进行欺骗。它可以使用有关字数的假设(例如,所有内容都是32位的,如中所示)并了解有关的内容,因为实现这些内容是操作系统工作的一部分。如果您的操作系统可移植到其他平台,则它将编译为不同的变体,如syscall
,以处理这些情况
为什么我建议使用struct args
而不是您的方法?因为在操作系统中,在进行系统调用的用户和从函数指针表运行的实际代码之间有几层。如果您将这些参数显式地传递到每一层,您将复制它们几次。如果第一层可以简单地提供一个指针,将参数“跳转”到中间函数上。如果您处理的是ABI,其中调用约定是将参数推送到堆栈上,则可以避免完全复制参数,只需将适当的堆栈地址作为参数
在McKusick等人设计和实现的4.4 BSD操作系统中,您可以找到关于这一点以及操作系统设计的几乎所有其他方面的讨论。如果您可以找到较旧的4.3版本,那么它实际上是一个相当小的卷,并且仍然与您正在进行的工作完全相关。除非有必要,否则没有必要您正在做一些提供接口的事情,通常为此您创建一个结构,该结构包含实现和设置适当指针所需的基本操作只需在枚举值上使用switch语句即可。在C中,大多数情况下,这会优化为跳转表,因为所有枚举值都是连续的,因此在基于某些请求参数检查要执行的函数时,不会出现管道暂停
例如,在Linux内核中,有一些具有预定义函数原型的基本操作结构,您所要做的就是实现这些函数,并导出一个结构,该结构将适当的函数指针设置到您的实现中,并且它是即插即用的,但对于您想要的功能来说,这样做似乎有些过分。在任何现代系统上,您都可以创建一个void*数组来保存函数指针。但是,这在ANSI C中是技术上未定义的行为。相反,您可以使用void(*)()之类的通用函数指针类型并在调用时将指针强制转换为正确的函数指针类型。但无论如何,您都需要一个switch语句来执行该强制转换,因此正如Jesus提到的,您可以在同一时间调用正确的函数并完全忘记数组。如果您愿意避免类型安全,您可以创建一个联合类型,如下所示:
union Args {
size_t st;
ssize_t sst;
int i;
unsigned u;
pid_t pt;
mode_t mt;
char *pc;
const char* cpc;
void *pv;
const void *cpv;
/* etc */
};
然后,对于每个函数,让它们接受union Args*
作为参数列表,接受size\u t
作为参数数(open可以接受3个参数-它使用va_*根据需要检查它们。让它们返回union Args
)
注意:对于void
函数,只需让它们返回0
例如
然后你可以得到一些大致如下的东西:
typedef union Args (*My_func)(union Args *, size_t);
My_func *fptrs;
您能举例说明如何调用它们吗?使用指向函数的指针:int*func(int a);但是不同的函数使用不同类型的参数。那么
arg1、arg2、argx的类型是什么呢?在32位系统上,您只需要依赖所有参数(int和指针)适合32位参数。结构中的类型本身并不重要,只是它们被函数强制转换为什么。非常感谢你的评论。我想我会同意Ben的结构思想。但是我仍然需要使用switch语句来调用函数。但是这很容易跟踪,除非你给它们所有相同的原型在这种情况下,您可以使用一个数组来调用它们,只需使用枚举值进行索引。谢谢您的评论。这真的很有帮助。
union Args my_open(union Args *args, size_t nargs) {
union Args a;
switch (nargs) {
case 2:
a.i = open(args[0].cpc, args[1].i);
break;
case 3:
a.i = open(args[0].cpc, args[1].i, args[2].mt);
break;
default:
errno = EINVAL;
a.i = -1;
}
return a;
}
typedef union Args (*My_func)(union Args *, size_t);
My_func *fptrs;