7

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

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

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

有关的

多语言如何在一个项目中交互?

4

7 回答 7

13

这个问题没有一个在任何地方都有效的单一答案。一般来说,答案是两种语言必须就“某事”达成一致——一组或规则或“调用协议”。

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

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

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

有时这两种语言会协同工作。有时这两种语言同意支持一些外部定义的协议。如今,操作系统或“运行时环境”(.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 的协议一样。毕竟,这都是关于与用不同语言编写的代码交谈(并且在不同的盒子中运行!)

于 2009-05-08T17:50:28.287 回答
4

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

于 2009-05-08T17:20:56.237 回答
4

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

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

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

于 2009-05-08T17:29:59.163 回答
2

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

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

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

于 2009-05-08T17:37:28.053 回答
1

如果您实际上是在寻找工具来做这样的事情,就像亚当的回应,请参阅swig

于 2009-05-08T17:34:04.957 回答
1

From a theoretical point of view, when program A need to use resources(class/functions/etc) from program B, it's about passing in some information from A to B, and get some information back or some actions performed. So there needs to be a way provided by B that allows A to pass in information and get result.

In practice, it usually lies on the shoulder of languages to handle this process: the language B(program B is written in) will generate a protocol and make resources in B available in a predefined way, then language A(program A is written in) will provide some utility/framework to help invocate the exposed resources and get results following B's protocol.

To be more specific to your question, for interpreted languages, the process is fairly universal, the protocol is normally among the lines of command line parameter, HTTP request and other ways of transmitting plain text. Take the first example, program B will receive a call from HTTP request as input, and then process the request from there on. The actual format of input is totally decided by program B.

Things like SOAP and etc, are just a way to regulate programs to take input in a commonly agreed standard.

于 2009-05-08T20:08:42.823 回答
1

It's been a decade or so, but I did exactly this for my senior capstone (Well, I built a back-propogating neural network in C, and used a scheme program to teach it). The version of Scheme I was using had a compiler as well as an intepreter, and I was able to build it as a .o file. I don't know the version of scheme I was running, but it appears the RScheme will turn your scheme code into C.

于 2009-05-08T20:26:18.227 回答