如何用fork/exec系列API实现C语言一元运算程序的链式调用?
基于进程API实现链式调用的方案
需求回顾
现有三个独立可执行程序:
./double <num>:输出输入整数的翻倍值(示例:./double 3输出output:6)./root <num>:输出输入整数的平方根(示例:./root 9输出output:3)./square <num>:输出输入整数的平方值(示例:./square 9输出81)
需要实现链式调用:输入命令如./chain square root square double 8时,执行逻辑为double(square(root(square(8)))),最终输出结果128。要求仅使用fork、exec*系列、str*系列、ato*系列、printf/sprintf、round这些API,且父进程必须等待子进程退出。
核心实现思路
链式调用的本质是前一个进程的输出作为后一个进程的输入参数,因此需要:
- 父进程逐个创建子进程,顺序执行每个操作(必须等待前一个子进程完成才能启动下一个)
- 通过管道捕获子进程的标准输出,提取数值后作为下一个子进程的命令行参数
- 完成数值与字符串的双向转换(
exec*仅接受字符串参数)
完整代码实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Usage: %s <operation1> <operation2> ... <initial_value>\n", argv[0]); return 1; } // 初始化初始值 double current_val = atof(argv[argc - 1]); char num_str[64]; // 遍历所有操作,依次执行 for (int i = 1; i < argc - 1; i++) { int pipefd[2]; // 创建管道,用于捕获子进程输出 if (pipe(pipefd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:重定向stdout到管道写端 close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); // 将当前数值转为字符串,作为子进程的命令行参数 sprintf(num_str, "%.2f", current_val); // 执行对应的操作程序 if (strcmp(argv[i], "square") == 0) { execl("./square", "square", num_str, NULL); } else if (strcmp(argv[i], "root") == 0) { execl("./root", "root", num_str, NULL); } else if (strcmp(argv[i], "double") == 0) { execl("./double", "double", num_str, NULL); } // 如果exec执行失败,打印错误并退出 perror("exec failed"); exit(EXIT_FAILURE); } else { // 父进程:读取管道中的子进程输出 close(pipefd[1]); char buffer[64]; ssize_t read_len = read(pipefd[0], buffer, sizeof(buffer) - 1); if (read_len > 0) { buffer[read_len] = '\0'; // 去掉输出中的换行符 buffer[strcspn(buffer, "\n")] = '\0'; // 处理带"output:"前缀的输出,提取纯数值部分 char *val_str = buffer; char *prefix = strstr(buffer, "output:"); if (prefix != NULL) { val_str = prefix + strlen("output:"); } // 转换为double类型,作为下一个操作的输入 current_val = atof(val_str); } close(pipefd[0]); // 等待子进程完全退出 waitpid(pid, NULL, 0); } } // 打印最终结果 printf("Result: %.2f\n", current_val); return EXIT_SUCCESS; }
关键细节说明
- 管道的使用:每个子进程的标准输出被重定向到管道写端,父进程从管道读端读取输出,实现进程间的数据传递。
- 顺序执行保证:父进程通过
waitpid等待每个子进程退出后,才会处理下一个操作,确保链式调用的顺序依赖关系。 - 输出格式兼容:代码会自动识别并跳过"output:"前缀,兼容不同程序的输出格式。
- 错误处理:对管道创建、fork失败的情况做了错误捕获,避免程序异常退出。
内容的提问来源于stack exchange,提问作者timp bill
相关产品推荐
相关产品推荐

