如何通过popen()等待子进程执行完毕后再读取其stdout?
解决方法:先读取输出,再等待子进程并获取返回码
不需要把stdout写入文件,调整操作顺序就能解决问题:先把子进程的输出全部读到缓冲区保存起来,再调用_pclose()等待子进程结束并获取返回码,之后根据返回码决定是否使用之前保存的输出内容。
原因很简单:_popen()创建的管道会缓存子进程的输出,直到子进程结束或者缓冲区填满。只要在调用_pclose()之前完成读取,就能拿到完整的输出内容,不会因为_pclose()销毁FILE指针而丢失数据。
修正后的代码示例
#include <cstdio> #include <string> #include <cstring> int main() { std::string command = std::string("slangc -o ") + "my_shader_frag.spv " + "my_shader_frag.slang"; command += " 2>&1"; // 将stderr重定向到stdout,统一读取 FILE* file = _popen(command.c_str(), "r"); if (!file) { // 处理_popen失败的情况 return 1; } char my_buffer[5000]; std::string output; size_t bytes_read; // 循环读取所有输出,避免一次读不完 while ((bytes_read = fread(my_buffer, 1, sizeof(my_buffer) - 1, file)) > 0) { my_buffer[bytes_read] = '\0'; // 确保字符串终止 output += my_buffer; } // 等待子进程结束并获取返回码 int exit_code = _pclose(file); // Windows下_pclose返回子进程的退出码,若子进程正常退出,exit_code就是其返回值;若出错返回-1 bool success = (exit_code == 0); if (!success) { // 非成功状态,使用保存的输出(错误信息) printf("编译失败,错误信息:\n%s\n", output.c_str()); } else { // 编译成功,可选处理输出(如果有的话) printf("编译成功\n"); } return 0; }
关键细节说明
- 循环读取:
fread()不一定能一次读完所有输出,所以要循环读取直到返回0,确保拿到完整的子进程输出。 - 缓冲区安全:每次读取时预留一个字节放终止符
\0,避免字符串溢出。 - 返回码处理:Windows平台下
_pclose()的返回值就是子进程的退出码,直接判断是否为0即可知道编译是否成功;如果是Linux平台,需要用WEXITSTATUS(exit_code)来获取实际的退出码(因为pclose()返回的是包含终止状态的整数值)。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

