std::system 最快启动且支持 shell 语法,但无法获取输出或控制进程;返回值为终止状态,需用 WEXITSTATUS 或判断是否为 -1。

用 std::system 最快启动,但无法获取输出或控制进程
如果只是想“跑个命令然后等它结束”,std::system 是最直接的选择。它会调用系统 shell(Windows 是 cmd.exe,Linux/macOS 是 /bin/sh),所以支持管道、重定向、分号拼接等 shell 语法。
常见错误是忽略返回值含义:std::system 返回的是进程的终止状态(不是退出码本身),需用 WEXITSTATUS(POSIX)或直接判断是否为 -1(失败):
#include <cstdlib>
#include <iostream>
int main() {
int ret = std::system("ls -l /tmp");
if (ret == -1) {
std::cerr
</iostream></cstdlib>
- Windows 下传入含空格路径时,必须用双引号包裹整个命令字符串,比如
std::system("dir "C:\Program Files"") - 不能捕获 stdout/stderr,也无法向子进程写入输入
- 存在 shell 注入风险——若命令字符串拼接了用户输入,务必先清理或改用更安全方式
Linux/macOS 用 fork+exec 精确控制子进程
需要读取外部程序输出、设置环境变量、重定向文件描述符,或避免 shell 解析时,必须绕过 std::system,走 POSIX 原生流程。
核心步骤固定:先 fork 创建子进程 → 子进程中调用 exec 系列函数(如 execvp)替换当前镜像 → 父进程用 waitpid 同步。
-
execvp会自动在$PATH中查找可执行文件,参数是char*[],末尾必须为nullptr - 若要捕获 stdout,需在
fork前用pipe创建管道,再在子进程中用dup2将stdout重定向到写端 - 子进程应显式调用
_exit(非exit),避免刷新父进程的 stdio 缓冲区导致重复输出
Windows 上用 CreateProcess 替代 fork/exec
Windows 没有 fork,等效方案是 CreateProcess。它参数多、易出错,关键点集中在字符串和句柄管理上。
最常踩的坑是 lpCommandLine:它必须是可修改的非常量缓冲区(即使你只读),且命令和参数必须拼成单个字符串(如 "ping -n 1 127.0.0.1"),不能像 POSIX 那样传 argv 数组。
-
STARTUPINFO中的hStdOutput等字段仅在dwCreationFlags包含CREATE_NO_WINDOW或DETACHED_PROCESS且bInheritHandles=TRUE时才生效 - 子进程继承句柄后,父进程需关闭写端,否则
ReadFile不会因子进程退出而返回 EOF - 获取退出码必须调用
GetExitCodeProcess,不能依赖WaitForSingleObject的返回值
C++17 起没有标准跨平台进程 API,别指望
虽然 C++20 提案中曾讨论 ,但它被延期至 TS 或未来版本,目前所有主流编译器(GCC、Clang、MSVC)均未实现。网上搜到的 std::process::spawn 示例全是假想代码或第三方库封装。
实际项目中,要么自己封装 fork/exec 和 CreateProcess 的抽象层,要么引入成熟库:
-
boost::process:功能完整,支持流重定向、信号控制、环境隔离,但 Boost 依赖较重 -
ghc::filesystem不提供进程控制;std::filesystem更不相关 - 轻量场景可考虑
tiny-process-library(header-only,MIT 协议)
跨平台代码里混用 system 和条件编译看似省事,但 shell 行为差异(如 Windows dir vs Linux ls)、路径分隔符、编码问题会让调试成本陡增。真要跨平台,尽早统一用底层 API 或可靠封装库。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











