我试图在C中编写一种调度函数,它应该接收一个由函数名组成的字符串,然后从调度函数内部调用函数,以便能够调用在接收到的参数中指定名称的函数。重点是我不想在动态加载的库中定义函数。流程应该是这样的。
file1.c中
void hello()
{
fprintf(stderr,"Hello world\n");
}
void myfunc()
{
mydispatch("hello");
}
file2.c中
void mydispatch(const char *function)
{
...
}
我知道这种结构可能有点奇怪,但我主要想知道是否可以做到这一点。
答案 0 :(得分:2)
您可以使用BFD从符号名称获取运行时的地址。
#include <stdio.h>
#include <stdlib.h>
#include <bfd.h>
#include <string.h>
void func1(int n)
{
printf("%d\n", n);
}
void * addr_from_name(char * filename, char * symname)
{
bfd * ibfd;
asymbol ** symtab;
symbol_info info;
void * symaddress = NULL;
long size;
long syms;
unsigned int i;
bfd_init();
ibfd = bfd_openr(filename, NULL);
bfd_check_format(ibfd, bfd_object);
size = bfd_get_symtab_upper_bound(ibfd);
symtab = malloc(size);
syms = bfd_canonicalize_symtab(ibfd, symtab);
for(i = 0; i < syms; i++) {
if(strcmp(symtab[i]->name, symname) == 0) {
bfd_symbol_info(symtab[i], &info);
symaddress = (void *)info.value;
}
}
bfd_close(ibfd);
return symaddress;
}
int main(void)
{
void (*func)(int) = addr_from_name("/homes/mk08/Desktop/lala", "func1");
printf("%p\n", func);
func(5);
return EXIT_SUCCESS;
}
在这种情况下,我硬编码filename
,但动态获取它是微不足道的。假设您的源/二进制文件被称为lala
,您可以像这样编译和运行:
gcc -Wall -std=gnu99 lala.c -o lala -lbfd && ./lala
在我的系统上,打印:
0x400814
5
请注意,此方法需要完整的符号表。为了减少开销,您可以在初始化例程中重用上面的代码。在那里,您将存储从函数名称到地址的映射。这导致生成查找表的一次性成本。
答案 1 :(得分:0)
你当然可以这样做:
void mydispatch(const char *function)
{
if (!strcmp(function, "hello")
hello();
else if (!strcmp(function, "goodbye")
goodbye();
}
你会和你在一起;许多语言翻译是在古代以这种方式建造的。
就做更动态的事情而言:必要的运行时结构根本不适用于静态链接的库。无论你做什么,你都必须手动或自动创建某种调度表(就像我在这里展示的那样) - 但你必须自己做。
答案 2 :(得分:0)
也许您正在寻找以下类型的解决方案:
file1.c中:
void myfunc()
{
my_function_type fun = search_function( "operation1" );
fun();
}
的Tools.h:
typedef void (*my_function_type)( void );
void register_function( my_function_type fp, const char* name );
my_function_type search_function( const char* name );
file2.c中:
static void mydispatch( void )
{
...
}
static void __attribute__ ((constructor)) register_functions()
{
register_function( mydispatch, "operation1" );
}
在该解决方案中,添加功能时无需再次编译旧文件。 只需编译新文件并链接。