【发布时间】:2014-12-05 11:44:38
【问题描述】:
在linux上(例如),我们可以直接使用OS提供的api(open/close/read/write)进行系统调用,也可以在C中使用libc提供的函数(fopen等)。
在其他语言中是如何实现的?
【问题讨论】:
标签: operating-system programming-languages system-calls
在linux上(例如),我们可以直接使用OS提供的api(open/close/read/write)进行系统调用,也可以在C中使用libc提供的函数(fopen等)。
在其他语言中是如何实现的?
【问题讨论】:
标签: operating-system programming-languages system-calls
在其他语言中,这通常(总是?)通过围绕本机函数调用的包装器来实现。实际上,它看起来像这样。 LanguageX -> Wrapper -> 本机代码(C/C++)
有时此包装器采用整个框架的形式,例如在 JNI 中用于 java。 这也适用于 Groovy 脚本。
使用某些语言,您可以以类似于 C/C++ 的方式将本机 DLL 直接加载到您的应用程序中。在 Python 使用 ctypes 的情况下确实如此。
其他时候,根本不需要本地调用,并且可以直接使用您选择的语言产生相同的结果。跨平台 GUI 工具包是一个可以完全替换本地操作系统调用的小例子。比如用 GTK 或 QT
希望能把事情搞清楚 :) 如果您想要任何其他特定于语言的详细信息,请告诉我。
【讨论】:
您最初的前提是错误的:在 Linux 上,当您在 C 代码中调用 open(2) 时,您不是进行系统调用,而是调用 glibc 提供的函数(或您的程序碰巧使用的 C 标准库的任何实现——还有其他的,例如μLibc、dietlibc 等),并且该函数的实现实际上使系统调用——正确地进行必要的设置以符合到目标架构的ABI 约定。
您可以在 C 中直接进行系统调用,但它看起来与仅调用 open() 大不相同;一些指针是this 和this。
回顾一下:the POSIX standard(指定open(2) 和朋友的外观和行为方式)只指定了一个相当高级的接口(就 C 编程语言而言),但实现该标准的具体内核具有他们自己的系统调用集和关于如何调用它们的约定(在同一内核的 H/W 架构之间有所不同),它是 C 标准库,它“知道”如何调用一个具体的内核来确保 C 程序调用 POSIX API 最终会使用经过适当设置的适当系统调用。换句话说,在 Linux 上运行的典型 C 应用程序中,您并没有直接处理系统调用——您只是有一个印象。
其他语言/运行时基本上有两种选择:
libc 并依赖它在它们和内核之间进行调解。我所知道的大多数语言/运行时都采用第一条路线(Python、Java 等等),而其中一些采用另一条路线——例如,Go、Free Pascal 的参考实现。
2014-10-13 更新回答@tan 评论中的问题:
那么,如果采用第一条路由(libc),如何从python/java调用libc函数?
基本上,该方法类似于系统调用的方法:再次调用 C,对于硬件体系结构和 C 编译器的每种组合都是标准化的。请参阅this discussion 了解更多信息和更多指示。
请注意,实际上,大多数能够与 C 代码交互的软件都使用以下两种方法之一:
它本身是用 C 语言编写的,因此在外部 C 代码中实现对动态或静态链接的调用由编译调用软件的编译器处理。
也就是说,您的软件必须关心的唯一事情是正确地安排其数据由 C 端操作。一个例子是确保传递给 C 端的内存块在 C 端完成之前不会被垃圾回收。
Go 编程语言的cgo subsystem 就是这种方法的一个例子。
调用软件使用一个库(通常用 C 编写以利用 C 编译器可以为它做的事情),该库能够加载 C 动态库并正确调用它们的函数来执行所有必需的数据设置。请参阅this 了解更多信息。
Python 的 ctypes 模块正是实现了这种方法。
我很难将 Java 的 JNI 和 .NET 的 P/Invoke 分为这两类。可能他们坐在中间的某个地方。
【讨论】: