Может кто-нибудь объяснить, что делает dup() в C?
Я знаю, что dup, dup2, dup3 "создают копию дескриптора файла oldfd" (из man-страниц). Однако я не могу переварить это.
Как я знаю, файловые дескрипторы - это просто числа для отслеживания местоположения файлов и их направления (ввод / вывод). Не было бы проще просто
fd=fd2;
Всякий раз, когда мы хотим дублировать дескриптор файла?
И что-нибудь еще..
dup () использует неиспользуемый дескриптор с наименьшим номером для нового дескриптора.
Означает ли это, что он также может принимать значение stdin, stdout или stderr, если мы предположим, что у нас есть один из них close()?
8 ответов
Просто хотел ответить себе на второй вопрос после того, как немного поэкспериментировал.
Ответ ДА. Созданный вами файловый дескриптор может принимать значение 0, 1, 2, если stdin, stdout или stderr закрыты.
Пример:
close(1); //closing stdout
newfd=dup(1); //newfd takes value of least available fd number
Где это происходит с файловыми дескрипторами:
0 stdin .--------------. 0 stdin .--------------. 0 stdin
1 stdout =| close(1) :=> 2 stderr =| newfd=dup(1) :=> 1 newfd
2 stderr '--------------' '--------------' 2 stderr
Файловый дескриптор немного больше, чем число. Он также несет в себе различные полускрытые состояния (независимо от того, открыто оно или нет, к какому описанию файла оно относится, а также к некоторым флагам). dup
дублирует эту информацию, так что вы можете, например, закрыть два дескриптора независимо. fd=fd2
не.
Единственная самая важная вещь в dup() - возвращает наименьшее целое число, доступное для нового файлового дескриптора. Это основа перенаправления:
int fd_redirect_to = open("file", O_CREAT);
close(1); /* stdout */
int fd_to_redirect = dup(fd_redirect_to); /* magically returns 1: stdout */
close(fd_redirect_to); /* we don't need this */
После этого все, что записано в файловый дескриптор 1 (stdout), волшебным образом переходит в "файл".
Допустим, вы пишете программу оболочки и хотите перенаправить stdin и stdout в программу, которую хотите запустить. Это может выглядеть примерно так:
fdin = open(infile, O_RDONLY);
fdout = open(outfile, O_WRONLY);
// Check for errors, send messages to stdout.
...
int pid = fork(0);
if(pid == 0) {
close(0);
dup(fdin);
close(fdin);
close(1);
dup(fdout);
close(fdout);
execvp(program, argv);
}
// Parent process cleans up, maybe waits for child.
...
dup2 () - немного более удобный способ сделать это. close () dup () можно заменить на:
dup2(fdin, 0);
dup2(fdout, 1);
Причина, по которой вы хотите это сделать, заключается в том, что вы хотите сообщить об ошибках в stdout (или stderr), чтобы вы не могли просто закрыть их и открыть новый файл в дочернем процессе. Во-вторых, было бы напрасно тратить форк, если любой вызов open () вернул ошибку.
Пример:
close(1); //closing stdout newfd=dup(1); //newfd takes value of least available fd number
Где это происходит с файловыми дескрипторами:
0 stdin .--------------. 0 stdin .--------------. 0 stdin 1 stdout =| close(1) :=> 2 stderr =| newfd=dup(1) :=> 1 newfd 2 stderr '--------------' '--------------' 2 stderr
Вновь возник вопрос: как я могу
dup()
дескриптор файла, который я уже закрыл?
Я сомневаюсь, что вы провели вышеупомянутый эксперимент с показанным результатом, потому что это не соответствовало бы стандартам - ср. dup:
Функция dup() не будет работать, если:
[EBADF] Аргумент fildes не является допустимым дескриптором открытого файла.
Итак, после показанной кодовой последовательности, newfd
должно быть не 1
, скорее -1
, а также errno
EBADF
,
См. эту страницу, stdout может быть псевдонимом как dup(1)
...
Просто совет о "дублировании стандартного вывода".
В некоторых системах Unix (но не в GNU/Linux)
fd = open("/dev/fd/1", O_WRONLY);
это эквивалентно:
fd = dup(1);
Системный вызов dup() и dup2()
• Системный вызов dup() дублирует дескриптор открытого файла и возвращает новый дескриптор файла.
• Новый файловый дескриптор имеет следующие общие свойства с исходным файловым дескриптором: 1. относится к тому же открытому файлу или каналу. 2. имеет один и тот же файловый указатель - то есть оба файловых дескриптора имеют один файловый указатель. 3. имеет одинаковый режим доступа, будь то чтение, запись или чтение и запись.
• dup() гарантированно возвращает дескриптор файла с наименьшим доступным целочисленным значением. Именно из-за этой функции возвращается наименьший доступный дескриптор файла, который используется процессами для перенаправления ввода-вывода.
int dup (file_descriptor)
int dup2 (file_descriptor1, file_descriptor2)