【问题标题】:How does code written in one language get called from another language用一种语言编写的代码如何从另一种语言调用
【发布时间】:2009-05-08 17:15:09
【问题描述】:

这是一个我一直想知道答案但从未真正问过的问题。

由一种语言(尤其是解释型语言)编写的代码如何被编译型语言编写的代码调用。

例如,假设我正在用 C++ 编写游戏,并且我将一些 AI 行为外包给了用 Scheme 编写的。用 Scheme 编写的代码如何达到编译后的 C++ 代码可以使用的程度? C++ 源代码如何使用它,C++ 编译代码如何使用它?使用方式有区别吗?

相关

How do multiple-languages interact in one project?

【问题讨论】:

  • 最佳。姓名。永远。

标签: c++ programming-languages scheme compilation interpreter


【解决方案1】:

对于无处不在的问题,没有单一的答案。一般来说,答案是两种语言必须就“某事”达成一致——一组或规则或“调用协议”。

在高层次上,任何协议都需要指定三件事:

  • “发现”:如何找到彼此。
  • “linking”:如何建立联系(在他们相互了解之后)。
  • “调用”:如何实际向对方发出请求。

细节很大程度上取决于协议本身。

有时这两种语言会协同工作。有时这两种语言同意支持一些外部定义的协议。如今,操作系统或“运行时环境”(.NET 和 Java)也经常参与其中。有时该能力只适用于一种方式(“A”可以调用“B”,但“B”不能调用“A”)。

请注意,这与任何语言在与操作系统通信时所面临的问题相同。 Linux内核不是用Scheme编写的,你知道的!

让我们看看一些来自 Windows 世界的典型答案:

  • C 与 C++:C++ 使用“C 协议”的扭曲(“损坏”)变体。 C++ 可以调用 C,C 也可以调用 C++(尽管名称有时会很混乱,翻译名称可能需要外部帮助)。这不仅仅是 Windows;在支持两者的所有平台上通常都是如此。大多数流行的操作系统也使用“C 协议”。

  • VB6 与大多数语言:VB6 的首选方法是“COM 协议”。其他语言必须能够编写 COM 对象才能在 VB6 中使用。 VB6 也可以生成 COM 对象(尽管不是所有可能的 COM 对象变体)。

    VB6 也可以谈论“C 协议”的一个非常有限的变体,然后只能在外部进行调用:它不能创建可以直接通过“C 协议”与之交谈的对象。

  • .NET 语言:所有 .NET 语言都编译为相同的低级语言 (IL)。运行时管理通信,从这个角度来看,它们看起来都像是同一种语言。

  • VBScript 与其他语言:VBScript 只能处理 COM 协议的一个子集。

还有一点需要注意:SOAP“Web 服务”实际上也是一种“调用协议”,就像许多其他正在流行的基于 Web 的协议一样。毕竟,这都是关于与用不同语言编写的代码交谈(并且在不同的盒子中运行!)

【讨论】:

    【解决方案2】:

    通常,C++ 代码会调用脚本语言的解释器。编译代码和脚本代码之间的交互程度取决于解释器,但总有一种方法可以在两者之间传递数据。根据解释器的不同,可以从另一侧操作对象,例如调用 Ruby 对象上的方法的 C++ 函数。甚至可能有一种方法可以控制另一个的执行。

    【讨论】:

      【解决方案3】:

      有一个关于模块如何通信的协议。以下是对其工作原理的高层次、广泛的概述:

      1. 为您要“共享”的代码创建了一个库。这些通常称为 DLL 或 SO,具体取决于您的平台。
      2. 您要公开的每个函数(入口点)都可供外部世界绑定。有一些关于如何绑定的协议,例如调用约定,它指定传递参数的顺序、谁清理堆栈、有多少参数存储在寄存器中以及哪些参数等。有关调用示例,请参见 cdecl、stdcall 等约定here
      3. 然后调用模块将静态或动态绑定到共享库。
      4. 一旦调用库绑定到共享库,它就可以指定要绑定到特定入口点。这通常是按名称完成的,但是大多数平台也提供按索引绑定的选项(如果您的模块更改和入口点重新排序,速度更快,但更脆弱)。
      5. 您通常还会在模块中的某处声明要调用的函数,以便您的语言可以进行静态类型检查,知道调用约定是什么等。

      对于从 C++ 调用 Scheme 的场景,Scheme 解释器很可能会导出一个动态绑定到 Scheme 函数/对象并调用它的函数。如果 Scheme 模块已编译,它可能具有导出入口点的选项,以便您的 C++ 模块可以绑定到该入口点。我对 Scheme 不是很熟悉,所以其他人可能比我更好地回答特定绑定的细节。

      【讨论】:

      • 哈哈哈!!嗨火花!很想在这里见到你。 (文斯)
      • 嗨,文斯!好久没见到你了你最近过得怎么样(在 FB 上联系我)?
      【解决方案4】:

      您还可以集成这两个环境,而无需在可执行文件中编译解释器的库。您将 exe 和 Scheme exe 作为单独的程序保存在系统上。从您的主 exe 中,您可以将您的方案代码写入文件,然后使用 system() 或 exec() 来运行方案解释器。然后解析方案解释器的输出。

      上面建议的方法将 exe 分开,您不必担心第三方依赖项,它们可能很重要。问题也包含在一个或另一个 exe 中。

      如果运行单独的 exe 不能满足您的性能要求,您可以设计一个协议,将 Scheme 解释器变成服务器。您需要编写一些在套接字或文件上等待输入的 Scheme 函数,评估该输入,然后将结果输出到同一个套接字或不同的文件。另一个迭代是查看可能已经在运行您的解释器的现有服务器,例如 apache 具有允许以多种语言编写代码的模块。

      【讨论】:

        【解决方案5】:

        如果你真的在寻找工具来做这样的事情,就像亚当的回应,请参阅swig

        【讨论】:

          【解决方案6】:

          从理论上讲,当程序A需要使用程序B的资源(类/函数/等)时,就是将一些信息从A传递给B,然后取回一些信息或执行一些动作。所以需要B提供一种方式,允许A传递信息并获得结果。

          在实践中,通常由语言来处理这个过程:语言 B(编写程序 B)将生成协议并以预定义的方式使 B 中的资源可用,然后语言 A(程序 A被写入)将提供一些实用程序/框架来帮助调用暴露的资源并按照 B 的协议获得结果。

          为了更具体地回答您的问题,对于解释型语言,该过程是相当普遍的,协议通常在命令行参数、HTTP 请求和其他传输纯文本的方式之间。以第一个例子为例,程序 B 将接收来自 HTTP 请求的调用作为输入,然后从那里处理请求。输入的实际格式完全由程序B决定。

          诸如 SOAP 之类的东西只是一种规范程序以接受普遍认可的标准输入的方式。

          【讨论】:

            【解决方案7】:

            已经有十年左右的时间了,但我正是为我的高级顶点所做的(嗯,我用 C 语言构建了一个反向传播神经网络,并使用了一个方案程序来教授它)。我使用的 Scheme 版本有一个编译器和一个解释器,我能够将它构建为一个 .o 文件。我不知道我正在运行的方案版本,但似乎 RScheme 会将您的方案代码转换为 C。

            【讨论】:

              猜你喜欢
              • 2014-02-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-04
              • 2011-01-04
              • 2012-06-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多