4

我想做应用程序,它可以用外部模块编译,例如在 php.ini 中。在php中,你可以在运行时加载模块,或者将php与模块一起编译,这样模块就可以在运行时不加载。但我不明白如何做到这一点。如果我在 module.c 中有一个模块并且有一个名为 say_hello 的函数,如果你明白我的意思,我如何将它注册到主应用程序?

/* module.c */
#include <stdio.h>

// here register say_hello function, but how, if i can't in global scope
// call another function?

void say_hello() 
{
  printf("hello!");
}

如果我将所有这些文件(主应用程序 + 模块)编译在一起,则不会从主应用程序中引用 say_hello 函数,因为只有当用户在其代码中调用它时才会调用它。所以我怎么能对我的应用说,嘿,有 say_hello 函数,如果有人想调用它,你知道它存在。

EDIT1:我需要在运行时有类似表的东西,在那里我可以看到用户调用的函数是否存在(有 C equivavent)。头文件对我没有帮助。

EDIT2:我的应用程序是为我的脚本语言解释的。

EDIT3:如果有人在php中调用函数,php解释必须知道该函数存在。我知道动态链接,如果加载了 .so 或 .dll,则调用一些启动例程,您可以在该 dll 中简单地注册函数,因此 php 解释可以看到,如果某些模块注册了例如名为“say_hello”的函数。但是,如果我想用例如 gd 支持编译 php,那么如何将 gd 函数注册到一些 php 函数列表、哈希表或其他什么?

4

4 回答 4

2

我猜您正在寻找的是动态库(我们通常将运行时可加载模块称为 C 和 OS 世界中的动态/共享库)。以Pidgin为例,它支持插件来扩展其功能。它为它的插件制造商提供了一个特定的接口来遵守,比如注册、加载、卸载和使用的功能,插件必须遵循这些功能。

当程序加载时,它会在其plugins目录中查找此类动态库,如果存在,它将加载并使用它,否则它将跳过公开功能。需要接口的原因是因为不同的模块可以具有不同的功能,这些功能在运行时之前是未知的,所以一个应用程序。必须有一个共同的,商定的方式来“交谈”它的插件/模块。

每个 C 程序都可以链接到静态或动态库;static 会将代码从库中复制到所述程序中,这样就不会留下程序运行的依赖关系,而链接到动态库则希望动态库在程序启动时存在。第三种方法是不链接到 DLL,而只是要求操作系统执行库的加载操作。如果成功,则使用动态模块,否则忽略。只有当加载调用成功时,动态库应该执行的功能才会向用户公开。

需要注意的是,这是操作系统提供的功能,与使用的语言无关(C 或 C++ 或 Python 在这里无关紧要);就 C 而言,编译器仍然链接到已知代码,即在编译时可用的代码。这就是不同操作系统的原因,需要编写不同的代码来加载一个动态模块。更重要的是,syuch 库的文件类型/格式因系统而异。在 Linux 中称为共享对象 (.so),在 Mac 中称为动态库 (.dylib),在 Windows 中称为动态链接库 (.dll)。

于 2012-12-26T14:27:40.703 回答
1

你需要的是动态库。我们首先看一下dlopen(3) 的 Linux 手册页中提供的示例:

/* Load the math library, and print the cosine of 2.0: */
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

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

    handle = dlopen("libm.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();    /* Clear any existing error */

    /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
       would seem more natural, but the C99 standard leaves
       casting from "void *" to a function pointer undefined.
       The assignment used below is a workaround. */

    *(void **) (&cosine) = dlsym(handle, "cos");

    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

    printf("%f\n", (*cosine)(2.0));
    dlclose(handle);
    exit(EXIT_SUCCESS);
}

还有一个C++ dlopen mini HOWTO

有关动态加载的更多一般信息,请首先从维基百科页面开始。

于 2012-12-26T14:41:14.680 回答
1

C 不是解释语言。所以你需要链接,你可能需要静态链接或动态链接。

程序构建包括两个主要阶段:编译和链接。在编译期间,所有 c 文件都被翻译成机器代码,而调用的函数(objo文件)则未被解析。然后链接器将所有这些文件合并到一个可执行文件中,解决未解决的问题。

这是静态链接。链接模块成为可执行文件的组成部分。

动态链接是特定于平台的。在 Windows 下,这些是 DLL。您应该发出系统调用来加载 DLL,之后您将能够从中调用函数。

于 2012-12-26T14:20:40.513 回答
-5

如果我明白你的意思,我认为这是不可能的。因为它是编译语言。

于 2012-12-26T14:22:21.610 回答