【问题标题】:how to store output from "bc" into a variable?如何将“bc”的输出存储到变量中?
【发布时间】:2013-12-02 10:24:50
【问题描述】:

这个程序应该做的是问用户一个简单的算术问题,例如5 + 7 然后用“bc”检查答案(是否正确)。

我有以下代码,但我不明白如何编辑它以将“5 + 7”的结果存储到变量中(当前结果进入 STDOUT)。

欢迎任何帮助。

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

int main( int argc, char *argv[], char *env[] )
{

    char *expr = "5 + 7\n";
    int answer;

    printf("%s = ", expr);
    scanf("%d", &answer);


    int pfds[2];
    pipe(pfds);

    if (!fork()) {
        close(1);       /* close normal stdout */
        dup(pfds[1]);   /* make stdout same as pfds[1] */
        close(pfds[0]); /* we don't need this */
        printf("%s\n", expr);

        /***********************/
        /* How to store printf()'s output into a variable? */

        exit(0);
    } else {
        close(0);       /* close normal stdin */
        dup(pfds[0]);   /* make stdin same as pfds[0] */
        close(pfds[1]); /* we don't need this */
        execlp("bc", "bc", NULL);
    }


   return 0;
}

【问题讨论】:

  • 使用sprintf 打印到字符串。
  • 我没有看到将stdout 重定向到父进程中的管道的兴趣。如果唯一的兴趣是使用printf,最好使用fdopen 获取流并在其上调用fprintf,这样父进程就可以方便地使用其标准输出。

标签: c fork bc


【解决方案1】:

您需要创建第二个管道并在子进程中将stdout 重定向到它。

【讨论】:

  • 我知道这不是可取的,但你能用代码演示一下吗?
【解决方案2】:

您可以简单地读取 STOUD 或读取管道的输出。然后调用Read()Atoi 可能会完成这项工作。 Atoi 手册页here

我无法为你编写代码,但这里的逻辑

    `int fds[2];
     pipe(fds);
     dup2(fds[1], stdout);
     read(fds[1], buf, buf_sz);
     int ResultOfbc = Atoi(buf)`

【讨论】:

    【解决方案3】:

    呜呜呜,我记得去年做的这件事。 我基本上是一个使用我自己的 telnet 克隆与互联网通信的程序。 问题是 telnet 使用 stdin 和 stdout 工作。

    看来你也有同样的情况! 我解决这个问题的方法是分叉一个进程,获取标准输入和标准输出并将它们放入管道中,然后使用 telnet 调用覆盖分叉的进程映像(现在使用这些管道而不是标准输入和标准输出)。

    您需要一个管道将文本发送到 bc,另一个管道从 bc 接收。 如果您对所有内容都使用单个管道,那么您最终可能会读取发送到 bc 的内容并混合数据。

    警告:大量代码传入。 我相信您不需要了解所有内容,因为我使用线程同时写入和读取,并使用 select() 来查看管道中是否有任何要读取的内容。 很重要!!!当通信中断时,您的进程将收到终止不干净的 SIGPIPE(如果您使用的是动态内存或类似的东西)。 你必须 fflush(outpipe) 否则 bc 不会收到它。 (这是因为系统只有在找到 '\n' 或类似的东西时才会刷新,如果我没记错的话)。 我放了所有代码,以防您想阅读 X 的作用。但是你需要的只是评论“LOCAL FUNCTIONS END HERE”之后的小叉

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <errno.h>
    #include <signal.h>
    #include <stdbool.h>
    #include "irc.h"
    #include "coloring.h"
    #include "rtsp.h"
    
    #define BUFFERSIZE 255
    int main (int argc, char *argv[]) {
    
    /* XXX: When kid dies, program doesn't exit */
    
    char *serverName, *port, *nick, *channel;
    int ptelnetin[2];
    int ptelnetout[2];
    FILE *fpipes[2];
    bool running = true;
    pid_t kid;
    pthread_t pthread_input, pthread_output;
    
    
    /************************************************
    
      LOCAL FUNCTIONS START HERE
    
      ***********************************************/
    
    
    
    void *inputprocess(void *pipes) {
    
        bool bracket;
        int i;
        fd_set rfds;
        struct timeval tv;
        tv.tv_sec = 0.2;
        tv.tv_usec = 0;
        char buffer[BUFFERSIZE];
        FILE *out = ((FILE **) pipes)[1];
    
    
        while (running){ 
            FD_ZERO(&rfds);
            FD_SET(fileno(stdin), &rfds);
            switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
                case -1:
                    fprintf(stderr, "Error reading data at select() Line %d, File %s\n", __LINE__, __FILE__);
                    running = false;
                    break;
    
                case 0: 
                    /* There's no data avaiable just yet.
                       Do nothing and keep checking */
                    break;
    
                default:
                    /* This check needs to be done;
                       select isn't completely reliable */
                    if(!fgets(buffer, BUFFERSIZE, stdin)) {
                        running = false;
                        break;
                    }
                    /* Check message not to contain brackets*/
                    for (i = 0, bracket = false; running && !bracket && buffer[i] && i < BUFFERSIZE; i++) {
                        if (buffer[i] == '[' || buffer[i] == ']') {
                            PRINT_YELLOW;
                            printf("Use of brackets not allowed\n");
                            RESET_COLOR;
                            fflush(stdout);
                            bracket = true;
                            break;
                        }
                    }
                    if (running && !bracket) ircInputWrite(out, buffer);
                    fflush(out);
            }
    
        }
    }
    
    void *outputprocess(void *pipes){
    
    
        fd_set rfds;
        struct timeval tv;
        tv.tv_sec = 0.2;
        tv.tv_usec = 0;
        char buffer[BUFFERSIZE];
        char from[100];
        FILE *in = ((FILE **) pipes)[0];
        FILE *out = ((FILE **) pipes)[1];
    
    
        while (running){ 
            FD_ZERO(&rfds);
            FD_SET(fileno(in), &rfds);
            switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
                case -1:
                    fprintf(stderr, "Error reading data at select() Line %d, File %s\n", __LINE__, __FILE__);
                    running = false;
                    break;
    
                case 0: 
                    /* There's no data avaiable just yet. */
                    /* Select sometimes returns 0 when there IS
                       data to read so we'll read anyway */
    
                default:
                    /* This check needs to be done;
                       select isn't completely reliable */
                    if(!fgets(buffer, BUFFERSIZE, in)) {
                        running = false;
                        break;
                    }
    
                    switch(ircWhatsthis(buffer)) {
                        case iPING:
                            PRINT_BLUE;
                            printf("PingPong!\n");
                            RESET_COLOR;
                            ircPingPong(out, buffer); fflush(out);
                            fflush(stdout);
                            break;
                        case iROOMMSG:
                            if (ircUnpackPRIVMSG(from, buffer, buffer)) {
                                PRINT_BRIGHT_RED;
                                fprintf(stdout, "Malformed private message received\n");
                                RESET_COLOR;
                            }
                            else {
                                PRINT_CYAN;
                                printf("<%s>: ", from);
                                puts(buffer);
                                RESET_COLOR;
                            }
    
                            fflush(stdout);
                            break;
    
                        case iPRIVMSG:
                            fflush(stdout);
                            if (ircUnpackPRIVMSG(from, buffer, buffer)) {
                                PRINT_BRIGHT_RED;
                                fprintf(stdout, "Malformed private message received\n");
                                RESET_COLOR;
                                fflush(stdout);
                            }
                            else {
                                if (rtspExecBrackets(out, from, buffer)) {
                                    PRINT_BRIGHT_MAGENTA;
                                    printf("[%s]: ", from);
                                    puts(buffer);
                                    RESET_COLOR;
                                    fflush(stdout);
                                }
                            }
    
                            break;
    
                        case iERROR:
                            PRINT_BRIGHT_RED;
                            fwrite(buffer, sizeof(char), strlen(buffer)+1, stdout);
                            RESET_COLOR;
                            break;
                        case iOK:
                            PRINT_BRIGHT_CYAN;
                            fwrite(buffer, sizeof(char), strlen(buffer)+1, stdout);
                            RESET_COLOR;
                            break;
                        default:
                            PRINT_BRIGHT_BLACK;
                            fwrite(buffer, sizeof(char), strlen(buffer)+1, stdout);
                            RESET_COLOR;
                    }
    
                    fflush(stdout);
            }
    
        }
    }
    
    void terminate(int signum) {
        /* XXX irc.c calls rtsp.c which uses threads.
           These threads never clean up if exiting via ^C
        */
        RESET_COLOR;
        running = false;
        /*Close IO*/
        fclose(fpipes[0]);
        fclose(fpipes[1]);
        /* Call child */
        kill(kid, SIGINT);
        wait(NULL);
        exit(0);
    
    }
    
    
    /************************************************
    
      LOCAL FUNCTIONS END HERE
    
     ***********************************************/
    
    signal(SIGPIPE, terminate);
    signal(SIGINT, terminate);
    
    
    
    /* Get parameters */
    if (argc != 5) {
        fprintf(stderr, "Usage:\n %s <server> <port> <nick> <channel>\n", argv[0]);
        return -1;
    }
    
    serverName = argv[1];
    port = argv[2];
    nick = argv[3];
    channel = argv[4];
    
    /* Startup pipes */
    pipe(ptelnetin);
    pipe(ptelnetout);
    
    /* Launch telnete */
    switch (kid = fork()) {
        case -1:
            perror("OMG ABORTION at main");
            exit(-2);
        case 0: /* CHILD */
            /*Overwrite stdin with pipein and discard pipe*/
            dup2(ptelnetin[0], 0);
            close(ptelnetin[0]);
            close(ptelnetin[1]);
            /*Overwrite stdout with pipeout and discard pipe*/
            dup2(ptelnetout[1], 1);
            close(ptelnetout[0]);
            close(ptelnetout[1]);
            /*Overwrite process image with telnete*/
            execlp("./telnete", "./telnete", argv[1], argv[2], (char *) NULL);
            perror("Call to exec failed at main");
            exit(-3);
        default: /* PARENT */
        /* Close reading end of pipein */
            close(ptelnetin[0]);
        /* Close writing end on pipeout */
            close(ptelnetout[1]);
    }
    
    
    /* Turn (fileno) into (FILE *) */
    fpipes[1] = fdopen(ptelnetin[1],"w");
    
    if(!fpipes[1]) {
        perror("Error at fdopen(in) at main");
        kill(kid, SIGINT);
        abort();
    }
    
    
    fpipes[0] = fdopen(ptelnetout[0],"r");
    if(!fpipes[0]) {
        perror("Error at fdopen(out) at main");
        kill(kid, SIGINT);
        abort();
    }
    
    
    
    
    /* Sleep for a few seconds so server doesn't ignore it */
    PRINT_YELLOW;
    printf("Logging in IRC...\n");
    RESET_COLOR;
    fflush(stdout);
    if (ircRegister(argv[3], fpipes[1], fpipes[0])) {
        fprintf(stderr, "Error registering in IRC.\n");
        terminate(-1);
    }
    
    PRINT_YELLOW;
    printf("Joining room %s\n", argv[4]);
    RESET_COLOR;
    ircJOIN(fpipes[1], argv[4]);
    fflush(fpipes[1]);
    
    
    /* Launch threads */
    if (pthread_create(&pthread_input, NULL, inputprocess, fpipes)){
        fprintf(stderr,"Couldn't launch input thread");
        kill(kid, SIGINT);
        abort();
    }
    if (pthread_create(&pthread_output, NULL, outputprocess, fpipes)){
        fprintf(stderr,"Couldn't launch output thread");
        kill(kid, SIGINT);
        abort();
    }
    
    /* Wait for threads */
    if (pthread_join(pthread_input,NULL)){
        fprintf(stderr, "Error joining thread.\n");
    }
    if (pthread_join(pthread_output,NULL)){
        fprintf(stderr,"Error joining thread.\n");
    }
    
    
    terminate(0);
    
    
    
    
    
    }
    

    我会把关键片段放在这里,这样更清楚:

    /* Startup pipes */
    pipe(ptelnetin);
    pipe(ptelnetout);
    
    /* Launch telnete */
    switch (kid = fork()) {
        case -1:
            perror("OMG ABORTION at main");
            exit(-2);
        case 0: /* CHILD */
            /*Overwrite stdin with pipein and discard pipe*/
            dup2(ptelnetin[0], 0);
            close(ptelnetin[0]);
            close(ptelnetin[1]);
            /*Overwrite stdout with pipeout and discard pipe*/
            dup2(ptelnetout[1], 1);
            close(ptelnetout[0]);
            close(ptelnetout[1]);
            /*Overwrite process image with telnete*/
            execlp("./telnete", "./telnete", argv[1], argv[2], (char *) NULL);
            perror("Call to exec failed at main");
            exit(-3);
        default: /* PARENT */
        /* Close reading end of pipein */
            close(ptelnetin[0]);
        /* Close writing end on pipeout */
            close(ptelnetout[1]);
    }
    
    
    /* Turn (fileno) into (FILE *) */
    fpipes[1] = fdopen(ptelnetin[1],"w");
    
    if(!fpipes[1]) {
        perror("Error at fdopen(in) at main");
        kill(kid, SIGINT);
        abort();
    }
    
    
    fpipes[0] = fdopen(ptelnetout[0],"r");
    if(!fpipes[0]) {
        perror("Error at fdopen(out) at main");
        kill(kid, SIGINT);
        abort();
    }
    

    完成此操作后,您可以从 (FILE *) fpipes[0] 读取 bc 的结果并将其写入 fpipes[1]。 记住每次写入后都要 fflush(fpipes[1]) 。 像对待任何文件一样对待这两个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-09
      • 2018-01-27
      • 2023-02-13
      • 2011-10-08
      • 2021-12-11
      相关资源
      最近更新 更多