系统调用与函数调用

时间:2010-04-19 15:38:14

标签: c system-calls function-calls

系统调用和函数调用有什么区别? fopen()是系统调用还是函数调用?

10 个答案:

答案 0 :(得分:30)

系统调用是对内核代码的调用,通常通过执行中断来执行。中断导致内核接管并执行请求的操作,然后将控制权交还给应用程序。此模式切换是系统调用执行速度低于等效应用程序级函数的原因。

fopen是C库中的一个函数,它在内部执行一个或多个系统调用。通常,作为C程序员,您很少需要使用系统调用,因为C库会为您包装它们。

答案 1 :(得分:9)

fopen是一个函数调用。

系统调用与管理资源的底层操作系统交互。它的数量级比函数调用更昂贵,因为必须采取许多步骤来保持进行系统调用的进程状态。

在* nix系统上,fopen打开,这使得系统调用(open是系统调用的C - 包装器)。 fread / read,fwrite / write等会发生同样的情况。

Here有一个很好的描述unix系统调用执行的任务。

答案 2 :(得分:6)

实际上,系统调用与函数调用无关。这两种机制中唯一常见的是它们都为呼叫者提供服务。

  • 从线程执行的角度来看系统调用:

    系统调用是应用程序模式程序的功能,用于请求由下划线OS提供的服务。系统调用将运行线程从用户模式带入内核模式,执行系统调用处理函数,然后返回用户模式。

  • Syscall参数:

    系统调用的参数是(系统调用号,参数...)。 params的含义和格式取决于系统调用号。

  • 从提供给用户程序的系统调用库的视图:

    用户模式程序通常调用glibc的库来调用系统调用。例如,glibc中的open()函数:

    1. 将系统调用号SYS_OPEN放入eax寄存器
    2. 通过调用软件中断或sys_enter指令请求系统调用

答案 3 :(得分:3)

如果您使用的是Linux,则可以监控应用程序执行的系统调用:

strace appname ...

它的输出可以让你很好地了解libc中发生了什么,以及哪些函数实际上是系统调用。

答案 4 :(得分:2)

System call实际上调用了内核空间执行的API。假设所有相关成本(请参阅Wiki或此链接以获取详细信息)

函数调用是对用户空间中的一段代码的调用。

但请注意,一个函数调用可能是一个函数,它在执行过程中会进行系统调用 - “fopen”就是其中一个例子。因此,虽然对fopen本身的调用是对函数的调用,但并不意味着系统调用不会发生处理实际的IO。

答案 5 :(得分:2)

添加到本讨论中的一个观点是,在最乐观的情况下,函数调用在x86中具有几个8位指令(平均4-10个)的开销。

系统调用具有以下属性。

  1. 它执行更多指令,它必须冻结进程而不是简单的堆栈状态。
  2. 所涉及的时间主要是非确定性的。
  3. 通常是一个调度点,调度程序可能会选择重新安排。
  4. 由于这三个原始原因(可能还有更多),应尽可能减少系统调用量 - 例如,联网系统软件将套接字句柄(以及连接使用的其他应用程序特定内部数据结构)保持在分配给新连接,为什么要打扰内核?

    请记住,软件的构建就像一个颠倒的金字塔。系统调用位于基础。

答案 6 :(得分:2)

这个问题已经有了很好的答案,但我想我可以添加一些东西(来自ostep的一段不在其他答案中

有时系统调用和函数调用具有相同的签名,例如open()

open() - 系统调用

--- ~/Documents » man open(2)

OPEN(2)                 Linux Programmer's Manual           OPEN(2)

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
...

open() - 函数调用

$ man open(3)

--- ~/Documents » 
OPEN(3P)                        POSIX Programmer's Manual          OPEN(3P)
...

int open(const char *path, int oflag, ...);

...

引用表单OSTEP

  

您可能想知道为什么拨打系统调用(例如open()read())看起来与典型的程序调用完全相同C;也就是说,如果它看起来就像一个程序调用,系统如何知道它是系统调用,并做了所有正确的事情?原因很简单:它是一个程序调用,但隐藏在程序调用中的是着名的陷阱指令。更具体地说,当您调用open()(例如)时,您正在对C库执行过程调用。其中,无论是提供open()还是任何其他系统调用,库都使用与内核达成一致的调用约定来将参数置于众所周知的位置(例如,在堆栈或特定的寄存器)中,将系统调用号码放入一个众所周知的位置(再次, 堆栈注册),然后执行上述陷阱指令陷阱解压缩后,库中的代码返回值并将控制权返回给发出系统调用的程序。因此,进行系统调用的C库部分是在汇编中手工编码的,因为它们需要仔细遵循约定,以便正确处理参数和返回值,以及执行硬件 - 特定的陷阱指令。现在您知道为什么您个人不必将陷阱的汇编代码写入操作系统;有人已经为你写了这个集会。

答案 7 :(得分:1)

fopen是函数调用,但有时可称为系统调用,因为它最终由“系统”(OS)处理。 fopen已内置{{1}}。

答案 8 :(得分:1)

为了完成其他人提供的图片,fopencommonly implemented作为open的包装,它也是一个用户可访问的功能。从某种意义上说,fopenopen更高级,因为它返回的FILE*结构会为用户封装内容。有些用户直接使用open来满足特殊需求。因此,以任何方式将fopen称为“系统调用”是不对的。它也不直接执行系统调用 ,因为open也是用户可调用的函数。

答案 9 :(得分:0)

系统调用在kernet级别执行,而不是在用户spce中执行,因为它需要一些权限才能访问硬件。

因此,在用户空间编程并在C语言中进行类似fopen的普通函数调用时,libc通常将此函数包装到特定的代码中,在该代码中生成中断以从用户空间切换到内核空间,然后在内核空间在硬件级别执行函数调用功能所需的系统调用将在内核空间中执行。