Почему stdio.h печатает запись в файл, открытый дескриптором файла? - PullRequest
0 голосов
/ 07 марта 2012

То, что я хочу записать в дескриптор файла - это строка ввода. Однако он также записывает сообщения об ошибках, переданные в fprintf. Может кто-нибудь объяснить, почему он так себя ведет? Эта небольшая программа показывает поведение.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    int fd;
    mode_t mode = S_IRUSR | S_IWUSR;
    char *filename = "file.txt";
    char *input = "hello world";
    char output[20];

    // create and close
    if((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1)
    {
        fprintf(stderr, "Error.\n");
        return -1;
    }
    close(fd);

    // just open
    if((fd = open(filename, O_RDWR, mode)) == -1)
    {
        fprintf(stderr, "Error.\n");
        return -1;
    }

    if(write(fd, input, 200) == -1)
    {
        fprintf(stderr, "Error.\n");
        return -1;
    }

    // move back to beginning
    if(lseek(fd, 0, SEEK_SET) == -1)
    { 
        return -1;
    }

    if(read(fd, &output, 200) == -1)
    {
        fprintf(stderr, "Error.\n");
        return -1;
    }

    printf("%s\n", output);

    return 0;
}

Ответы [ 5 ]

3 голосов
/ 07 марта 2012
write(fd, input, 200)

//...

read(fd, &output, 200)

Вы пишете и читаете хорошо за массивами, которые содержат допустимые данные - ни input, ни output не находятся где-либо рядом с 200 байтами. Итак, кто знает, что в итоге окажется в файле (и я не уверен, почему read() не приводит к сбою вашей программы)?

0 голосов
/ 07 марта 2012

Ввод не 200 символов в длину.Замените 200 на strlen (вход)

Или используйте этот макрос

#define write1(s) write(1, s, strlen(s))

Обратите внимание, вам нужно #include для strlen

0 голосов
/ 07 марта 2012

Звучит так, как будто ты close d stderr или что-то в этом роде. Так или иначе, fd и stderr содержат одно и то же целое число, поэтому и ваши write (который должен быть ошибочным), и fprintf используют один и тот же файловый дескриптор. Попробуйте проверить значение errno, возможно, используя perror или что-то еще, и посмотрите, есть ли там дополнительная информация.

В итоге, вы, вероятно, должны запустить его под отладчиком и посмотреть значения fd и stderr.

0 голосов
/ 07 марта 2012

Это не похоже на проблему с fd ... а скорее на ошибку памяти. Обратите внимание, что ваша строка формата не была заменена, но вы получили фактическую строку формата. Тот факт, что ваша запись использует block, а чтение использует &block, кажется немного подозрительным, хотя трудно сказать, если это все без контекста. Похоже, вы пишете память из вашей программы, которая, как оказалось, содержит строки вашей программы.

Я предлагаю запустить вашу программу с помощью valgrind.

ОБНОВЛЕНИЕ на основе добавленного кода:

read() и write() не работают с "строками", они будут записывать столько байтов, сколько вы просите. Ваш ввод - строковый литерал, и он намного меньше, чем 200 байтов ... Поскольку, скорее всего, все строковые литералы хранятся в одной и той же общей области в вашей программе, поэтому вы видите, что другие появляются в вашем выводе.

Несколько других проблем: ваш выходной буфер недостаточно велик для обработки запрошенного вами read(), и вы, вероятно, захотите использовать lseek() между записью и чтением, чтобы иметь возможность прочитать данные снова.

0 голосов
/ 07 марта 2012

Ставлю деньги, что 'fd' объявляется или как-то странно ограничен.дескриптор файла в UNIX - это просто целое число от 0 до некоторого максимального значения (раньше было 20, теперь оно намного больше), которое является индексом в таблице.STDIN==0, STDOUT==1 и STDERR==2.

Если вы видите поведение, которое вы описываете, то fd равно == 2.

...