2013-12-02 2 views
1

Что должна делать эта программа, так это задать пользователю простой арифметический вопрос, например. 5 + 7, а затем проверить ответ на «bc» (правильно ли он).Как сохранить выход из «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; 
} 
+0

Используйте 'sprintf' для печати в строку. – sgarizvi

+0

Я не вижу заинтересованности в перенаправлении 'stdout' на канал в родительском процессе. Если единственным интересом является использование 'printf', было бы лучше использовать' fdopen' для получения потока и называть 'fprintf' на нем, поэтому родительский процесс будет поддерживать его stdout. – Medinoc

ответ

1

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

+1

Я знаю, что это не предпочтительнее, но вы могли бы продемонстрировать код? – Tool

0

Вы можете просто прочитать STOUD или прочитать на выходе вашей трубы. Тогда вызов Read() и Atoi может выполнить эту работу. Atoi люди страницы here

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

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

Не могли бы вы показать его с кодом? – Tool

0

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

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

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

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

#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 из fpipes (FILE *) [0] и напишите ему в fpipes [1]. Запомните fflush (fpipes [1]) после каждой записи. Относитесь к этим двум, как к любому файлу.

Смежные вопросы