gpt4 book ai didi

c - 模块化编译时数组扩展

转载 作者:太空狗 更新时间:2023-10-29 15:32:07 27 4
gpt4 key购买 nike

假设我处于这种情况:

main.c :

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

#include "header.h"

int iCanProcess (char* gimmeSmthToProcess);

int processingFunctionsCount = 0;
int (*(*processingFunctions)) (char*) = NULL;

int addProcessingFunction(int (*fct)(char*)) {
processingFunctionsCount++;
processingFunctions = realloc(processingFunctions,
sizeof(int (*)(char*))*ProcessingFunctionsCount);
processingFunctions[processingFunctionsCount-1] = fct;
}

int main(int argc, char *argv[]) {
char* dataToProcess = "I am some veeeery lenghty data";
addProcessingFunction(iCanProcess);

[ ... ]

for(unsigned int i = 0; i < processingFunctionsCount; i++) {
processingFunctions[i](dataToProcess);
}

free(processingFunctions);
return 0;
}

int iCanProcess (char* gimmeSmthToProcess) { ... }

somefile.c :

 #include "header.h"

int aFunction(char* someDataToProcess) { ... }

header.h :

  #ifndef HEADER_DEF
#define HEADER_DEF

extern int processingFunctionsCount;
extern int (*(*processingFunctions)) (char*);

int addProcessingFunction(int (*fct)(char*));

#endif

有什么方法可以使用宏或任何其他技巧,将 aFunction 添加到函数指针数组 processingFunctions 而无需更改 main.cheader.h 每次我需要添加一个?

这里的问题不是更改数组,因为它可以很容易地重新分配,而是不更改 main() 函数:必须有一种方法我可以知道文件在这里并且编译,并在 main()

之外获取函数原型(prototype)

我考虑过使用像 this one 这样的预处理器技巧但似乎没有找到合适的方法...

(旁注:这是一个更大项目的精简版,它实际上是支持具有相同输出但不同输入的解析器的基本代码。一些解析器支持某些类型的文件,所以我有一个数组函数指针(每个解析器一个,以检查它们是否兼容),我根据文件内容调用它们中的每一个。然后,我要求用户选择它想要使用的解析器。每个解析器我有一个文件,包含一个“检查”功能,以查看解析器是否可以处理此文件,以及一个“解析”功能来实际完成所有艰苦的工作。每次添加解析器时我都无法更改 header 或 main.c 文件.)

(旁注 2:这个标题太糟糕了……如果您有更好的想法,请哦,请随意编辑它并删除此注释。谢谢)

最佳答案

您可以使每个函数成为一个模块(Windows 的共享对象或 dll),并带有一个已知名称的符号,然后在运行时简单地扫描一个目录以查找 .sos 或 .dlls 加载每一个并创建一个指向符号的指针,假设您有 N 个模块,其中第 i模块源码为

module.i.c

int function(char *parameter)
{
// Do whatever you want here
return THE_RETURN_VALUE;
}

然后你将每个 .c 文件编译成一个共享对象,我将使用 Linux 来说明在 Windows 上你可以做类似的事情,而 linux 解决方案适用于 POSIX 系统,所以它涵盖了很多

首先用这个脚本生成module.i.c文件

#!/bin/bash

for i in {0..100};
do
cat > module.$i.c <<EOT
#include <stdlib.h>

int
function(char *parameter)
{
// Deal with parameter
return $i;
}
EOT
done

现在创建一个像这样的Makefile

CC = gcc
LDFLAGS =
CFLAGS = -Wall -Werror -g3 -O0
FUNCTIONS = $(patsubst %.c,%.so, $(wildcard *.*.c))

all: $(FUNCTIONS)
$(CC) $(CFLAGS) $(LDFLAGS) main.c -o main -ldl

%.so: %.c
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@

clean:
@rm -fv *.so *.o main

以及加载模块的程序(我们假设它们与可执行文件位于同一目录)

#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>

int
main(void)
{
DIR *dir;
struct dirent *entry;
dir = opendir(".");
if (dir == NULL)
return -1;
while ((entry = readdir(dir)) != NULL)
{
void *handle;
char path[PATH_MAX];
int (*function)(char *);
if (strstr(entry->d_name, ".so") == NULL)
continue;
if (snprintf(path, sizeof(path), "./%s", entry->d_name) >= sizeof(path))
continue;
handle = dlopen(path, RTLD_LAZY);
if (handle == NULL)
continue; // Better: report the error with `dlerror()'
function = (int (*)(char *)) dlsym(handle, "function");
if (function != NULL)
fprintf(stdout, "function: %d\n", function("example"));
else
fprintf(stderr, "symbol-not-found: %s\n", entry->d_name);
dlclose(handle);
}
closedir(dir);
return 0;
}

在 Windows 上,想法是一样的,虽然你不能像上面的代码那样遍历目录,你需要使用 LoadLibrary()而不是 dlopen(),并将 dlsym() 替换为适当的函数。

但同样的想法也行得通。

有关如何保护您加载的模块及其文件夹的更多信息,请参阅 this question

关于c - 模块化编译时数组扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34700873/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com