You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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,且父进程必须等待子进程退出。

核心实现思路

链式调用的本质是前一个进程的输出作为后一个进程的输入参数,因此需要:

  1. 父进程逐个创建子进程,顺序执行每个操作(必须等待前一个子进程完成才能启动下一个)
  2. 通过管道捕获子进程的标准输出,提取数值后作为下一个子进程的命令行参数
  3. 完成数值与字符串的双向转换(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;
}

关键细节说明

  1. 管道的使用:每个子进程的标准输出被重定向到管道写端,父进程从管道读端读取输出,实现进程间的数据传递。
  2. 顺序执行保证:父进程通过waitpid等待每个子进程退出后,才会处理下一个操作,确保链式调用的顺序依赖关系。
  3. 输出格式兼容:代码会自动识别并跳过"output:"前缀,兼容不同程序的输出格式。
  4. 错误处理:对管道创建、fork失败的情况做了错误捕获,避免程序异常退出。

内容的提问来源于stack exchange,提问作者timp bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:20:47