使用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; }
核心错误分析
- 进程退出状态的数值限制:
exit(result)传递的退出状态仅能保留8位无符号整数(范围0-255),当运算结果超过255时(比如8先被doubleVal转为16,平方后得到256),256会被截断为0,这就是./double square 8输出0的直接原因。 - 操作执行逻辑混乱:代码默认先执行一次
doubleVal,但未匹配命令行参数的预期逻辑。比如./double square 2本应直接计算2的平方,却先将2转为4再平方,与用户预期不符。 - 字符串匹配冗余且易出错:逐个字符判断操作名的方式既繁琐又容易出现下标错误,比如漏判字符串结束符或字符位置写错。
修复后的代码
#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; }
修改说明
- 替换进程退出状态为管道传递:使用管道(pipe)在父子进程间传递整数结果,彻底解决退出状态仅能传递0-255的限制,支持任意范围内的整数运算。
- 修正操作执行逻辑:移除默认执行
doubleVal的冗余逻辑,严格按照命令行参数中的操作顺序执行,匹配用户预期。 - 简化字符串匹配:使用
strcmp函数替代逐个字符判断的方式,代码更简洁且不易出错。 - 增加参数校验:添加命令行参数数量检查,提示正确的使用方式。
内容的提问来源于stack exchange,提问作者timp bill
相关产品推荐
相关产品推荐

