C 在编译时使用函数指针而不知道原型

C 在编译时使用函数指针而不知道原型,c,linux,dlopen,C,Linux,Dlopen,从中,我学到了一个非常令人兴奋的事实,即您可以从共享库加载和运行代码,而无需显式地使用它编译程序 下面的代码片段演示了如何使用dlopen和关联函数从C的数学库libm运行double cosdouble函数: #include <stdlib.h> #include <stdio.h> #include <dlfcn.h> int main(int argc, char **argv) { void *handle; double (*co

从中,我学到了一个非常令人兴奋的事实,即您可以从共享库加载和运行代码,而无需显式地使用它编译程序

下面的代码片段演示了如何使用dlopen和关联函数从C的数学库libm运行double cosdouble函数:

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

int main(int argc, char **argv) {
    void *handle;
    double (*cosine)(double);
    char *error;

    handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);
    if (!handle) {
        fputs (dlerror(), stderr);
        exit(1);
    }

    cosine = dlsym(handle, "cos");
    if ((error = dlerror()) != NULL)  {
        fputs(error, stderr);
        exit(1);
    }

    printf ("%f\n", (*cosine)(2.0));
    dlclose(handle);
}
作为一种爱好,我一直在用C编写一个自定义语言的解释器,我想让用户能够选择一个共享库并从中运行代码。我知道这是可能的,因为许多语言,包括Python和J,都是用C编写的,都可以使用dlopen动态调用函数,只知道在运行时传递给函数和从函数返回什么

但是,我无法提前预测如何强制转换从dlsym返回的void指针。在上面的代码中,程序员知道他们要查找cos的符号是一个函数,使用一个double作为参数并返回一个double,因此他们知道如何将cosine变量转换为指向函数的指针,该函数接受一个double并返回一个double

如果我想编写一个程序,其中用户将指定文件名和函数原型,那么如何编写底层C代码来调用dlsym并正确调用函数


我的理论是,您需要直接从进程堆栈中推送参数和弹出返回值,如果没有内联汇编,我不知道该怎么做,这是我想要避免的,但由于您可能需要通过寄存器传递参数,这一点变得复杂。有人知道如何处理这个问题吗?

有一个著名的库来解决这个问题,许多解释语言都使用它:


内部,这个库当然使用汇编代码,但是它有这么多的HW和SW后端,你可以认为它是一个可移植的解决方案。

感觉有点相关:C语言本身不支持这个;它只能使用汇编或C之外的其他方法完成,可能包括在汇编中执行必要操作的外部例程。可能最“简单”的方法是,一旦用户给了你函数原型,你的程序就会把调用函数的C源代码写到一个文件中。源代码将在您设计的函数体中。然后使用诸如system之类的例程运行C编译器和其他实用程序,使用dlopen将结果链接到程序中,然后调用例程。例程将有一个固定的参数列表,包括指向union数组的指针,其中union包含您要支持的每种可能类型的成员。因此,您可以通过该数组将任意参数传递给例程,它将为您调用所需的例程。这都是一个粗糙的乱七八糟的问题,通常只对学习和实验有用。Perl和Python等语言将需求放在它们调用的函数的接口上。不能加载任意C库并调用其函数;您必须编写或生成一个可由脚本语言调用的粘合层,并封送参数、调用目标C函数和适当地处理响应。@JonathanLeffler