【问题标题】:System() calls in C++ and their roles in programmingC++ 中的 System() 调用及其在编程中的作用
【发布时间】:2010-10-28 09:23:24
【问题描述】:

我经常听说使用system("PAUSE") 是不好的做法,而是使用std::cin.get()。现在我对系统调用的理解是,它们将一个字符串输入系统命令行并与操作系统对话,因此 PAUSE 是一个 DOS 命令,可以暂停命令窗口中的输出。我认为这与具有不同关键字的 Mac 和 unix 类似,并且由于缺乏跨操作系统兼容性,不鼓励使用系统调用。 (如果我有任何错误,请纠正我)

我的问题是:什么时候适合使用 system() 调用?它们应该如何应用?什么时候不应该应用它们?

【问题讨论】:

  • 那么,进展如何,突然间你想“嘿,真的是时候对一年多前提交的问题进行一些修饰了”? :)

标签: c++ windows operating-system system dos


【解决方案1】:

system("PAUSE") 肯定不太理想。使用对系统的调用会创建一个子进程,这在 Windows 上是相当昂贵的,并且无论如何在任何操作系统上都不是非常便宜。在嵌入式系统上,内存开销很大。

如果有任何方法可以在本地没有太多痛苦,那就去做吧。在等待用户按下单个按钮的情况下,cin.get() 将很难被击败。在这种情况下,您的应用程序进程只会阻塞标准输入,只设置内核可见的几个标志,最重要的是,不会分配新内存,也不会创建新的调度实体,甚至不会创建中断处理程序。

此外,它在具有所有 c++ 编译器的所有操作系统上都可以正常工作,因为它仅使用该语言非常标准部分的一个非常基本的特性,而不依赖于操作系统提供的任何东西。

编辑:预测您担心它是否昂贵并不重要,因为整个 想法 是暂停。好吧,首先,如果它很贵,那么它会损害可能发生的其他任何事情的性能。有没有注意到(在 Windows 上)当一个应用程序启动时,其他已经打开的应用程序也变得不那么响应了?此外,您的用户可能不是一个活生生的人,而是另一个代表人类用户工作的程序(例如,一个 shell 脚本)。该脚本已经知道下一步该做什么,并且可以在标准输入中预先填充一个字符以跳过等待。如果您在此处使用了子进程,则脚本将经历(人类可察觉的)延迟。如果脚本这样做数百(或数亿!)次,则可能需要几秒钟才能运行的脚本现在需要数天或数年。

EDIT2:何时使用system():当你需要做一些其他进程做的事情时,你不能轻易做到。 system() 并不总是最好的候选人,因为它做了两件有些限制的事情。首先,与子进程通信的唯一方法是通过命令行参数作为输入,返回值作为输出。第二个是父进程阻塞,直到子进程完成。这两个因素限制了系统可用的情况。

在 unixy 系统上,大多数子进程都使用fork,因为它允许同一个程序作为两个独立进程在同一个地方继续,一个作为另一个进程的子进程(除非您从操作系统)。在 Linux 上,这特别优化,并且与创建 pthread 一样便宜。即使在速度不那么快的系统上,它仍然非常有用(正如 apache 进程池方法所证明的那样)(在 windows/link to unix docs 上不可用)

其他情况(在 Windows 上也是如此!)通常由 popenexec 系列函数处理。 popen 创建一个子进程和一个连接到子进程的标准输入或标准输出的全新管道。然后,父进程和子进程都可以同时运行并很容易地进行通信。 (link to windows docs/link to unix docs)

exec* 系列函数(有几个,execl,execv 等)另一方面会导致当前程序被新程序替换。原始程序不可见地退出,新进程接管。当新进程返回时,它将返回到任何所谓的原始进程,就好像该进程在那个时候已经返回而不是消失一样。与exit(system("command")) 相比,它的优势在于不会创建新进程,从而节省时间和内存(尽管并不总是非常多)(link to windows docs /link to unix docs)

system 可能被某些脚本工具用于调用某些配方操作中的多个步骤。例如,在某个时刻,程序可以使用system 调用文本编辑器来编辑某个配置文件。它不需要太关心发生的事情,但它当然应该等到用户保存并关闭编辑器后再继续。然后它可以使用返回值来确定编辑会话是否成功,即编辑器实际上打开了请求的文件(并且编辑器本身根本存在!),但将从中读取会话的实际结果直接编辑文件,而不是与子进程通信。 (link to windows docs/link to unix docs)

【讨论】:

  • exec和system对环境变量的处理有区别吗?
  • @Thomas L Holaday:exec 的某些变体允许您指定不同的环境变量,其他变体使用当前环境。系统始终使用当前环境。
【解决方案2】:

系统调用被发送到操作系统的 shell 或命令行解释器(dos、bash 等),并由 shell 执行它想要使用此命令执行的操作。

您应避免使用此类调用,因为这会降低您的程序与其他操作系统一起使用的可移植性。只有当您完全确定您的代码针对的是您应该使用此类调用的特定操作系统时,我才会认为。

【讨论】:

    【解决方案3】:

    但我的问题是:什么时候适合使用 system() 调用?它们应该如何应用?

    当您无法使用自己的代码或库来完成您尝试做的事情时(或者实施它的成本超过了启动新流程的成本)。与 cin.get() 相比,system() 在系统资源方面的成本相当高,因此只能在绝对必要时使用它。请记住,system() 通常会同时启动一个全新的 shell 以及您要求它运行的任何程序,因此会启动两个新的可执行文件。

    【讨论】:

      【解决方案4】:

      顺便说一句,system() 调用不应该与设置了 SUIDSGID 位的二进制文件一起使用,引用自 @987654321 @:

      不要在带有 set-user-ID 或 set-group-ID 的程序中使用 system() 特权,因为某些环境变量的值很奇怪 可能被用来破坏系统的完整性。使用 exec(3) 系列 函数,但不是 execlp(3) 或 execvp(3)。 system() 不会, 事实上,使用 set-user-ID 或 set-group-ID 的程序可以正常工作 /bin/sh 是 bash 版本 2 的系统上的特权,因为 bash 2 启动时删除权限。

      【讨论】:

        【解决方案5】:

        system() 用于要求操作系统运行程序。

        为什么您的程序希望操作系统运行程序?嗯,有案例。有时,外部程序或操作系统命令可以执行在您自己的程序中难以完成的任务。例如,外部程序可以使用提升的特权或访问适当的数据格式来运行。

        system() 函数本身是相当可移植的,但您传递给它的命令字符串可能是非常特定于平台的——尽管可以从本地配置数据中提取命令字符串以使其与平台更加无关。

        fork()exec*()spawn*()CreateProcess() 等其他函数可以让您更好地控制运行外部程序的方式,但它们是特定于平台的,可能在您的平台上不可用选择。

        system("PAUSE") 是一个古老的 DOS 技巧,现在通常被认为是相当古怪的风格。

        【讨论】:

          【解决方案6】:

          据我所知 system("PAUSE") 是一个只有 Windows 的东西,这就是为什么它不受欢迎。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多