【问题标题】:How do programming languages call code written in another language?编程语言如何调用用另一种语言编写的代码?
【发布时间】:2014-02-11 05:50:44
【问题描述】:

对不起,如果这太模糊了。我最近在阅读有关 python 的 list.sort() 方法并读到它是出于性能原因用 C 编写的。

我假设 python 代码只是将一个列表传递给 C 代码,而 C 代码将一个列表传回,但是 python 代码如何知道将它传递到哪里或者 C 给了它正确的数据类型,并且C 代码如何知道它被赋予了什么数据类型?

【问题讨论】:

  • 主要的python实现是用C编写的,从某种意义上说,这意味着当你运行一个python程序时,你实际上是在运行一个带有very的C程序(解释器) i> 复杂的配置文件(你的程序)。因为运行的是 C 程序,所以您的“配置文件”可以与 C 交互。这就是为什么 JRuby 或 Jython 可以与 Java 库交互,或者 MacRuby 与 Cocoa 交互的原因。
  • 对于不是 python 或 C 的替代/通用答案,请参阅:stackoverflow.com/questions/4546941/…

标签: python c language-agnostic cpython


【解决方案1】:

Python 可以在 C/C++ 中扩展(更多信息here

这基本上意味着你可以像这样包装一个 C 模块

#include "Python.h"

// Static function returning a PyObject pointer
static PyObject *
keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds) 
// takes self, args and kwargs.
{ 
    int voltage;
    // No such thing as strings here. Its a tough life.
    char *state = "a stiff";
    char *action = "voom";
    char *type = "Norwegian Blue";
    // Possible keywords
    static char *kwlist[] = {"voltage", "state", "action", "type", NULL};

    // unpack arguments
    if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|sss", kwlist,
                                     &voltage, &state, &action, &type))
        return NULL;
    // print to stdout
    printf("-- This parrot wouldn't %s if you put %i Volts through it.\n",
           action, voltage);
    printf("-- Lovely plumage, the %s -- It's %s!\n", type, state);

    // Reference count some None.
    Py_INCREF(Py_None);
    // return some none.
    return Py_None;
}
// Static PyMethodDef
static PyMethodDef keywdarg_methods[] = {
    /* The cast of the function is necessary since PyCFunction values
     * only take two PyObject* parameters, and keywdarg_parrot() takes
     * three.
     */
    // Declare the parrot function, say what it takes and give it a doc string.
    {"parrot", (PyCFunction)keywdarg_parrot, METH_VARARGS | METH_KEYWORDS,
     "Print a lovely skit to standard output."},
    {NULL, NULL, 0, NULL}   /* sentinel */
};

使用 Python 头文件,它将定义和理解 C/C++ 代码中的入口点和返回位置。

【讨论】:

    【解决方案2】:

    我不能直接谈论 Python/C 交互,但我可以提供一些背景知识来了解这些事情的一般工作原理。

    在特定平台或实现上,有一个 calling convention 指定如何将参数传递给子例程以及如何将值返回给调用者。针对该平台或实现的编译器和解释器生成符合该约定的代码,以便子例程/模块/以不同语言编写的任何内容都可以相互通信。

    在我的汇编课上,我们有一个作业,我们必须使用 VAX 汇编器、C 和 Pascal 编写程序(这是在白垩纪1980 年代中期)。驱动程序使用 C 或 Pascal 中的一个(不记得是哪一个了),它调用了汇编例程,后者调用了另一个例程(它是用驱动程序不是用哪种语言编写的)。我们的汇编代码必须根据 VMS 调用约定从堆栈中弹出和推送参数。

    【讨论】:

      【解决方案3】:

      每个计算平台都有(或应该有)一个应用程序二进制接口 (ABI)。这是对例程之间如何传递参数、如何返回值、机器应该处于什么状态等方面的规范。

      ABI 将指定诸如(例如)之类的内容:

      • 第一个整数参数(最多一些位,比如 32)将在某个寄存器(例如 %EAX 或 R3)中传递。第二个将在另一个特定的、寄存器中传递,依此类推。
      • 使用寄存器列表后,将在堆栈上传递额外的整数参数,从调用时堆栈指针值的某个偏移量开始。
      • 指针参数将被视为整数参数。
      • 浮点参数将在浮点寄存器 F1、F2 等中传递,直到这些寄存器用完,然后在堆栈中。
      • 如果复合参数(例如结构)非常小(例如,一个结构中有四个 char 对象),它们将作为整数参数传递,如果它们很大,则在堆栈中传递。

      每个编译器或其他语言实现都将生成符合 ABI 的代码,至少在其例程调用或从可能在该语言之外的其他例程调用的地方。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-01
        • 2011-07-16
        • 1970-01-01
        • 2011-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多