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

使用fork的链式运算程序执行./double square 8时结果异常求助

链式Fork运算程序逻辑错误排查

我编写了一个必须使用fork的链式运算程序(程序名为double.c),执行./double square 2时输出正确结果4,但执行./double square 8时输出0(预期结果应为256);尝试执行./double square square 8这类链式操作也无法正常工作,以下是我编写的代码,请求排查逻辑错误:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <math.h>

#include <sys/wait.h>
#include <stdlib.h>
#define EPSILON 0.001

double simple_abs(double x)
{
    return x > 0 ? x : -x;
}

double simple_sqrt(double x)
{
    double previous = 0;
    double guess = x;

    while (simple_abs(guess - previous) > EPSILON)
    {
        previous = guess;
        guess = previous - (previous * previous - x) / (2 * previous);
    }

    return guess;
}
int lop(int status) {
    return (status >> 8) & 0xff;
}

int square(int n) {
printf("number = %d  and square = %d", n , n*n);
    return n * n;
}

int root(int n) {
    return (int) simple_sqrt((double) n);
}

int doubleVal(int n) {
    return n * 2;
}

int main(int argc, char *argv[]) {
    int value = atoi(argv[argc - 1]);
    int result = value;
    if (argc > 2){
    result = doubleVal(result);
    for (int i = 1; i < argc - 1; i++) {
int pid = fork();
        if (pid == 0) {
            if (*argv[i] == 's' && *(argv[i]+1) == 'q' && *(argv[i]+2) == 'u' && *(argv[i]+3) == 'a' && *(argv[i]+4) == 'r' && *(argv[i]+5) == 'e' && *(argv[i]+6) == '\0'){
                result = square(result);
            } else if (argv[i][0] == 'r' && argv[i][1] == 'o' && argv[i][2] == 'o' && argv[i][3] == 't' && argv[i][4] == '\0')  {
                result = root(result);
            } else if (argv[i][0] == 'd' && argv[i][1] == 'o' && argv[i][2] == 'u' && argv[i][3] == 'b' && argv[i][4] == 'l' && argv[i][5] == 'e' && argv[i][6] == '\0') {
                result = doubleVal(result);
            } else {
                printf("Unknown operation: %s\n", argv[i]);
                exit(1);
            }
            exit(result);
        } else {
            int status;
            wait(&status);
            result = (status >> 8) & 0xff;
        }
    }
    }
    else {
    result = doubleVal(result);
    }

    printf("Result: %d\n", result);
    return result;
}

核心错误分析

  1. 进程退出状态的数值限制:exit(result)传递的退出状态仅能保留8位无符号整数(范围0-255),当运算结果超过255时(比如8先被doubleVal转为16,平方后得到256),256会被截断为0,这就是./double square 8输出0的直接原因。
  2. 操作执行逻辑混乱:代码默认先执行一次doubleVal,但未匹配命令行参数的预期逻辑。比如./double square 2本应直接计算2的平方,却先将2转为4再平方,与用户预期不符。
  3. 字符串匹配冗余且易出错:逐个字符判断操作名的方式既繁琐又容易出现下标错误,比如漏判字符串结束符或字符位置写错。

修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <math.h>
#include <string.h>

#define EPSILON 0.001

double simple_abs(double x)
{
    return x > 0 ? x : -x;
}

double simple_sqrt(double x)
{
    double previous = 0;
    double guess = x;

    while (simple_abs(guess - previous) > EPSILON)
    {
        previous = guess;
        guess = previous - (previous * previous - x) / (2 * previous);
    }

    return guess;
}

int square(int n) {
    return n * n;
}

int root(int n) {
    return (int) simple_sqrt((double) n);
}

int doubleVal(int n) {
    return n * 2;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "使用方式: %s [操作1] [操作2] ... <数值>\n", argv[0]);
        exit(1);
    }

    int result = atoi(argv[argc - 1]);

    // 按命令行顺序执行所有操作
    for (int i = 1; i < argc - 1; i++) {
        int pipefd[2];
        if (pipe(pipefd) == -1) {
            perror("pipe 创建失败");
            exit(1);
        }

        int pid = fork();
        if (pid == 0) {
            close(pipefd[0]); // 子进程关闭管道读端
            int op_result;

            // 使用strcmp简洁匹配操作名
            if (strcmp(argv[i], "square") == 0) {
                op_result = square(result);
            } else if (strcmp(argv[i], "root") == 0) {
                op_result = root(result);
            } else if (strcmp(argv[i], "double") == 0) {
                op_result = doubleVal(result);
            } else {
                fprintf(stderr, "未知操作: %s\n", argv[i]);
                exit(1);
            }

            // 通过管道传递结果,突破退出状态的数值限制
            write(pipefd[1], &op_result, sizeof(op_result));
            close(pipefd[1]);
            exit(0);
        } else {
            close(pipefd[1]); // 父进程关闭管道写端
            int status;
            wait(&status);
            if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
                read(pipefd[0], &result, sizeof(result));
            } else {
                fprintf(stderr, "子进程执行失败\n");
                exit(1);
            }
            close(pipefd[0]);
        }
    }

    printf("结果: %d\n", result);
    return 0;
}

修改说明

  1. 替换进程退出状态为管道传递:使用管道(pipe)在父子进程间传递整数结果,彻底解决退出状态仅能传递0-255的限制,支持任意范围内的整数运算。
  2. 修正操作执行逻辑:移除默认执行doubleVal的冗余逻辑,严格按照命令行参数中的操作顺序执行,匹配用户预期。
  3. 简化字符串匹配:使用strcmp函数替代逐个字符判断的方式,代码更简洁且不易出错。
  4. 增加参数校验:添加命令行参数数量检查,提示正确的使用方式。

内容的提问来源于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 20:50:29