Прочитать всю трубу - c

У меня есть некоторые трудности с этим кодом. Мне нужно получить всю информацию из канала на его конце. Но я получаю ошибку segfault.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(void){

    int tube[2];

    if(pipe(tube) == -1){
        perror("Erreur");
        exit(1);
    }

    dup2(tube[1],1);

    printf("Few lines \n");
    printf("of an undefined size. \n");

    while (!feof(tube[0])) {
        char temp = fgetc(tube[0]);
        printf("chaine : %c\n", temp);
    }

    return 0;
}

Если у вас есть идея, как я могу справиться с этой проблемой, пожалуйста, объясните.


person ztarky    schedule 24.04.2018    source источник
comment
Как справиться с такими проблемами, чтобы начать учиться использовать отладчик. Я не лукавлю: это важный навык для диагностики и устранения собственных проблем, не дожидаясь, пока люди в Интернете сделают это за вас. ;-)   -  person underscore_d    schedule 24.04.2018
comment
Аргумент fgetc() является FILE *. Ваш код передает int. Это вводит неопределенное поведение. Кроме того, fgetc() возвращает int, а не char. Наконец, есть много хороших объяснений того, почему цикл в стиле while (!feof()) является плохой техникой — Google поможет вам найти его.   -  person Peter    schedule 24.04.2018


Ответы (3)


Функция pipe возвращает пару файловых дескрипторов int, а не FILE. Это означает, что вы можете использовать на них read, write или close, но ни fgetc, ни feof.

Кроме того, while(!feof(file)) (почти) всегда неправильно, поскольку флаг устанавливается после неудачного чтение достигло конца файла.

И это еще не все. Вы получаете EOF только в конце канала для чтения, когда все дескрипторы в конце для записи закрыты. Таким образом, вы должны закрыть или сбросить stdout, чтобы убедиться, что все символы были записаны в канал, закрыть файловый дескриптор 1, если вы не закрыли стандартный вывод, и закрыть tube[1], который по-прежнему является файловым дескриптором для записи конца канала.

Таким образом, вы можете заменить цикл while на:

close(tube[1]);
fclose(stdout);

while (1) {
    char temp;
    if (read(tube[0], &temp, 1) < 1) break;
    fprintf(stderr, "chaine : %c\n", temp);
}

Он исправляет SEGFAULT, вызванный использованием feof и fgetc для чего-то, что не является FILE, и обеспечивает правильное закрытие конца записи файла перед чтением его содержимого, чтобы получить хорошее условие конца файла.

person Serge Ballesta    schedule 24.04.2018
comment
Если канал все еще пуст, функция read() заблокирует ожидание записи содержимого в канал, и процесс, как правило, зависнет. В этом ответе говорится, что: stackoverflow.com/a/8130971/4365678 Также вы можете прочитать об этом на странице руководства для канала : linux.die.net/man/7/pipe - person Ibrahim Mohamed; 29.12.2019

Но я получаю ошибку сегментации. ? это означает, что вы неправильно прочитали предупреждение компилятора. когда вы делаете feof(tube[0]), он говорит, что feof() ожидает FILE*, но вы предоставили тип int (tube[0] is inetger).

/usr/include/stdio.h:828:12: примечание: ожидается ‘struct FILE *’, но аргумент имеет тип ‘int’

Итак, первым делом всегда читайте предупреждения компилятора и компилируйте код с флагами -Wall.

Этот fgetc(tube[0]); не является способом чтения данных из file descriptor, используйте системный вызов read() для чтения данных из файловых дескрипторов, отличных от fgetc(). fgetc() вы можете использовать, если вы открыли файл с помощью fopen().

Также

dup2(tube[1],1); /* this is not expected one which you want*/

использовать вот так

dup2(1,tube[1]);/*stdout get duplicated with tube[1] i.e whatever you
                        write on stdout will be written into write end of pipe*/

Вот простой пример.

char temp[100];
        int ret = 0;
        ret = read(tube[0],temp,sizeof(temp));/*reading from pipe*/
        if(ret == -1)   {
                perror("read");
                return 0;
        }
        else {
                temp[ret] = '\0';/*read returns no of items read, so put null
                                        at last otherwise you may get some junk data  */
                printf("%s",temp);
        }

Прочтите man 2 read и man 2 dup2, чтобы узнать, как работают эти системные вызовы.

person Achal    schedule 24.04.2018

Вы используете функцию, которая возвращает один символ (fgetc), а затем обрабатываете это значение как указатель на строку в вашем вызове printf. Вы также сохраняете этот символ как адрес указателя на символ, а не как фактический символ, поэтому, когда printf переходит к чтению вашей строки, он считывает некоторую младшую память, которой он не владеет. fgetc возвращает сам символ, вам нужна переменная char, а не char*.

Пытаться:

while (!feof(tube[0])) {
    char temp = fgetc(tube[0]);
    printf("chaine : %c\n", temp);
}
person user2686305    schedule 24.04.2018
comment
Я всегда получаю segfault. Но да, это было заблуждение (вследствие этого я обновляю основной пост). Спасибо - person ztarky; 24.04.2018
comment
feof() и fgetc() ожидают указатели на потоки, а не дескрипторы файлов. Попробуйте создать поток с помощью fpopen(). - person user2686305; 24.04.2018