Почему 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