Почему close() системный вызов сбрасывает вывод?

Вот мой код:

#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 ответа

Решение

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

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

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

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

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

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

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

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

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

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

Я думаю, что вы не должны смешивать stdio и сырой write-с к тому же дескриптору записи. Рассмотреть возможность использования fdopen или жеfreopen

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