Как сохранить вывод из "bc" в переменную?

Предполагается, что эта программа должна задать пользователю простой арифметический вопрос, например, 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;
}

3 ответа

Решение

Вам нужно создать второй канал и перенаправить stdout к нему в дочернем процессе.

Вы можете просто читать STOUD или читать на выходе своей трубы. Затем вызов Read() и к Atoi может сделать работу. Страница Atoi man здесь

Я не могу написать это для вас, но здесь логика

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

Oof oof, этот материал, который я помню, делал в прошлом году. Я был в основном программой, которая использовала мой собственный клон telnet для связи с Интернетом. Проблема в том, что telnet использовал stdin и stdout для работы.

Похоже, у вас такая же ситуация! Чтобы решить эту проблему, я должен был обработать процесс, захватить stdin и stdout и поместить их в каналы, а затем перезаписать разветвленный образ процесса с помощью вызова telnet (который теперь вместо stdin и stdout использует эти каналы).

Вам нужен ОДИН канал для отправки текста на bc и ДРУГОЙ для получения от bc. Если вы используете один канал для всего, скорее всего, вы в конечном итоге прочитаете то, что отправили в bc, и смешаете данные.

ВНИМАНИЕ: МАССОВАЯ КОЛИЧЕСТВО ВХОДЯЩЕГО КОДА. Я уверен, что вам не нужно все понимать, так как я использую потоки, чтобы писать и читать одновременно, и выбираю (), чтобы посмотреть, есть ли что-то, что можно прочитать в канале. ОЧЕНЬ ВАЖНО!!! Когда связь прервется, ваш процесс получит SIGPIPE, который завершается не чисто (если вы используете динамическую память или что-то в этом роде). И вы ДОЛЖНЫ fflush(outpipe), иначе bc не получит его. (Это потому, что система сбрасывается только тогда, когда находит '\n' или что-то в этом роде, если я правильно помню). Я поместил весь код на тот случай, если вы захотите прочитать, что делает X. Но то, что вам нужно, это только маленькая вилка сразу после комментария "МЕСТНЫЕ ФУНКЦИИ ЗАКОНЧИТЕСЬ ЗДЕСЬ"

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

После этого вы можете прочитать результат bc из (FILE *) fpipes[0] и записать его в fpipes[1]. Не забывайте fflush(fpipes[1]) после каждой записи. Относитесь к этим двум, как к любому файлу.

Другие вопросы по тегам