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

有限系统调用下子进程向父进程传递大数值的实现方案

问题:子进程向父进程传递超出0-255范围的计算结果

我正在实现名为double.c的计算程序,仅允许使用fork、exec*系列、str*系列、ato*系列、printf/sprintf、round这些系统调用/函数。程序运行示例如下:

./double square 3
output:36 as square(double(3))

目前我使用exit(result)让子进程向父进程返回计算结果,但exit返回值范围仅为0-255,结果超过该范围时会出错(例如执行./double square 8时,结果256会被截断为0,导致返回值错误)。由于限制无法使用pipe、munmap等方法,请问如何在仅用指定函数的前提下传递更大数值?

我尝试的代码如下:

#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*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);
            }

       printf("Child result: %d\n", result);
       //return result;
            exit(result);
        } else {
            int status;
            wait(&status);
            //result = (status >> 8) & 0xff;
        result = lop(status);#lop is working as WEXITSTATUS system api 
        }
    }
    }
    else {
    result = doubleVal(result);
    }

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

解决方案:通过exec*传递结果作为命令行参数

放弃用exit传递数值的方案,转而利用exec*系列函数将计算结果以命令行参数的形式传递给新的进程实例,完全规避exit返回值的0-255限制。具体逻辑如下:

  1. 子进程完成当前计算后,将结果格式化为字符串,构造包含剩余操作和当前结果的新命令行参数数组。
  2. 子进程通过execvp调用当前程序的副本,传入新的命令行参数,让新进程继续处理剩余操作。
  3. 父进程只需等待子进程执行完成,无需获取exit状态,后续计算由exec后的进程接管,最终由最后一个进程输出结果。

修改后的代码示例

#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;
}

// 辅助函数:拼接操作链字符串,用于最终输出
void build_chain(char *dest, const char *op, const char *prev_chain) {
    if (prev_chain == NULL) {
        sprintf(dest, "%s(double(%%d))", op);
    } else {
        // 替换prev_chain中的%d为当前操作包裹的形式
        char temp[256];
        strcpy(temp, prev_chain);
        char *pos = strstr(temp, "%d");
        if (pos != NULL) {
            *pos = '\0';
            sprintf(dest, "%s%s(%%d)%s", temp, op, pos + 2);
        } else {
            sprintf(dest, "%s(%s)", op, prev_chain);
        }
    }
}

int main(int argc, char *argv[]) {
    // 检查是否有操作链参数(用于跟踪操作流程)
    char *chain = NULL;
    int value_idx = argc - 1;
    if (argc > 2 && strcmp(argv[1], "--chain") == 0) {
        chain = argv[2];
        value_idx = argc - 1;
        argc -= 2;
        argv += 2;
    }

    // 无剩余操作,输出最终结果
    if (argc == 2) {
        int value = atoi(argv[1]);
        int final_result = doubleVal(value);
        if (chain != NULL) {
            printf("output:%d as ", final_result);
            printf(chain, value);
            printf("\n");
        } else {
            printf("output:%d as double(%d)\n", final_result, value);
        }
        return 0;
    }

    int value = atoi(argv[value_idx]);
    int current_result;
    char *current_op = argv[1];

    // 先执行初始double操作,再处理当前操作
    int doubled_val = doubleVal(value);
    if (strcmp(current_op, "square") == 0) {
        current_result = square(doubled_val);
    } else if (strcmp(current_op, "root") == 0) {
        current_result = root(doubled_val);
    } else if (strcmp(current_op, "double") == 0) {
        current_result = doubleVal(doubled_val);
    } else {
        printf("Unknown operation: %s\n", current_op);
        return 1;
    }

    // 构造新的操作链
    char new_chain[256];
    build_chain(new_chain, current_op, chain);

    // 构造新的命令行参数数组
    int new_argc = argc + 1; // 增加--chain参数
    char **new_argv = malloc(sizeof(char*) * (new_argc + 1));
    if (!new_argv) {
        perror("malloc failed");
        return 1;
    }

    new_argv[0] = argv[0];
    new_argv[1] = "--chain";
    new_argv[2] = new_chain;
    // 复制剩余操作
    for (int i = 3; i < new_argc - 1; i++) {
        new_argv[i] = argv[i - 1];
    }
    // 转换当前结果为字符串
    char result_str[20];
    sprintf(result_str, "%d", current_result);
    new_argv[new_argc - 1] = result_str;
    new_argv[new_argc] = NULL;

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程执行新的命令
        execvp(new_argv[0], new_argv);
        // exec失败时的错误处理
        perror("execvp failed");
        exit(1);
    } else {
        // 父进程等待子进程完成
        int status;
        wait(&status);
        free(new_argv);
        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
            return 1;
        }
        return 0;
    }
}

运行示例

./double square 3
output:36 as square(double(3))

./double square 8
output:256 as square(double(8))

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