почему close () системный вызов сбрасывает вывод? - PullRequest
3 голосов
/ 06 декабря 2011

Вот мой код:

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char *argv[])
{
  int oldfd;
  int newfd;
  if(argc!=2)
  {
    printf("Usgae : %s file_name\n",argv[0]);
    exit(0);
  }
 oldfd=open(argv[1],O_RDWR|O_APPEND,S_IRWXU); // Opening the file in Read/Write mode
 if (-1 == oldfd)
 {
  perror("Error opening file");
  exit(0);
 }
 close(1); // closing stdout 
 newfd=dup(oldfd); //Now this newfd holds the value 1 
 close(oldfd); //closing the oldfd
 printf("\nStack Overflow"); //Now this printf will print content into the file as stdout closed already
 close(newfd);// closing newfd 
 return 0;
}

Что я на самом деле пытаюсь сделать, это просто напечатать «Переполнение стека» в файл, используя printf () вместо системного вызова write ().

Это не печать содержимого в файл. Но я заметил одну вещь: если я удалю код:

 close(newfd)

Он печатает содержимое в файл, как и ожидалось. Но я не могу понять почему. Я распечатал содержимое и только потом закрываю newfd.

В чем причина этого?

Ответы [ 3 ]

5 голосов
/ 06 декабря 2011

Здесь на самом деле происходит то, что вывод printf буферизуется и не отправляется на fd 1 немедленно;вместо этого буфер сбрасывается в дескриптор файла 1 во время выполнения C после возврата из main.Если вы close(newfd), вы фактически воспрепятствовали автоматическому сбросу, который в противном случае выполняется во время выполнения при выходе.

Если вы явно fflush(stdout) перед вами close(newfd), ваш вывод должен появиться вfile.

Кстати, если вы хотите перенаправить определенный дескриптор файла, существует альтернативный системный вызов dup2(oldfd, 1), который делает fd 1 дубликатом oldfd, закрывая fd 1, если он был ранее открыт.

0 голосов
/ 06 декабря 2011

close, write, open являются системными вызовами , которые в основном выполняются внутри ядра linux ; так что с прикладной точки зрения они являются элементарными атомарными операциями.

printf и fprintf - стандартные библиотечные функции, построенные над этими (и другими) системными вызовами.

Перед выходом -ing (например, возвращением из main) стандартная библиотека и окружение (в частности, код в crt*.o, вызывающий ваш main) выполняет функции, зарегистрированные atexit ; и стандартным вводом / выводом является (своего рода) регистрация вызова на fflush во время выхода. Таким образом, stdout является fflush -ed во время выхода. Если вы close его дескриптор в main, этот сброс завершается ошибкой и ничего не делаете.

Я думаю, вам не следует смешивать stdio и raw write -s с одним и тем же дескриптором записи. Попробуйте использовать fdopen или freopen

0 голосов
/ 06 декабря 2011

Когда вы используете дескрипторы файлов напрямую, вам нужно избегать , используя функции C stdio, такие как printf. Изменение основного дескриптора файла из-под слоя stdio кажется чреватым опасностью.

Если вы измените printf на следующее:

write(newfd, "\nStack Overflow", 15);

тогда вы, вероятно, получите ожидаемый результат (ваш close(newfd) или нет).

...