在 linux 上(例如),我们可以直接使用 OS 提供的 api(open/close/read/write)进行系统调用,也可以使用 C 中 libc 提供的函数(fopen 等)。
它是如何在其他语言中实现的?
最佳答案
你最初的前提是错误的:在 Linux 上,当你打电话时,比如说, open(2)
在您的 C 代码中,您不是在进行系统调用,而是调用 glibc
提供的函数。 (或您的程序碰巧使用的 C 标准库的任何实现——还有其他的,例如 μLibc 、dietlibc 等),并且该函数的实现实际上使系统调用——正确地进行必要的设置以符合到目标架构的ABI公约。
您可以直接在 C 中进行系统调用,但它看起来与仅调用 open()
有很大不同。 ;一些指针是this和 this .
回顾一下:the POSIX standard (指定 open(2)
和 friend 的外观和行为方式)只指定了一个相当高级的接口(interface)(就 C 编程语言而言),但实现该标准的具体内核有自己的一组系统调用和约定如何调用它们(在同一内核的 H/W 架构之间有所不同),它是 C 标准库,它“知道”如何调用一个具体的内核,它确保调用 POSIX API 的 C 程序最终使用适当的系统调用适当的设置。换句话说,在 Linux 上运行的典型 C 应用程序中,您并没有直接处理系统调用——您只是有一个印象。
其他语言/运行时基本上有两种选择:
libc
并依靠它在它们和内核之间进行调解。 我知道的大多数语言/运行时都采用第一条路线(Python、Java 等等),而其中一些采用另一条路线——例如,Go 的引用实现, Free Pascal .
2014 年 10 月 13 日更新 回答
@tan
的问题的评论:So, if the first route (libc) is taken, how are libc functions invoked from python/java?
基本上,该方法类似于系统调用的方法:再次调用 C 对于硬件体系结构和 C 编译器的每种组合都是标准化的。见 this discussion了解更多信息和进一步的指示。
请注意,实际上,大多数能够与 C 代码交互的软件都使用以下两种方法之一:
也就是说,您的软件唯一必须关心的是正确安排其数据以供 C 端操作。一个例子是确保传递给 C 端的内存块在 C 端完成之前不会被垃圾收集。
cgo
subsystem Go 编程语言的例子就是这种方法的一个例子。 Python的
ctypes
模块正是实现了这种方法。 我很难对 Java 的
JNI
进行分类和 .NET 的 P/Invoke
分为这两类。可能他们坐在中间的某个地方。
关于operating-system - 非 c 语言如何与操作系统交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26297151/