stdin
- это FILE *
, относящийся к структуре stdio (стандарт io), которая связана с файловым дескриптором 0
. Файловые дескрипторы - это то, что Unix-подобные системы, такие как Linux, используют для общения с приложениями о конкретных файловых вещах. (На самом деле, я почти уверен, что Windows это делает).
Файловый дескриптор 0
может относиться к любому типу файла , но для понимания этого должен быть вызван read
(это должен быть обычный файл, паровой сокет, или символьное устройство, открытое для чтения или сторона чтения канала, в отличие от файла каталога, сокета графа данных или блочного устройства).
Процессы в Unix-подобных системах наследуют дескрипторы открытых файлов от своих родительских процессов в Unix-подобных системах. Таким образом, чтобы запустить программу с установленным для stdin чем-то, кроме родительского stdin, вы должны сделать:
int new_stdin = open("new_stdin_file, O_RDONLY);
pid_t fk = fork();
if (!fk) { // in the child
dup2(new_stdin, 0);
close(new_stdin);
execl("program_name", "program_name", NULL);
_exit(127); // should not have gotten here, and calling exit (without _ ) can have
// side effects because it runs atexit registered functions, and we
// don't want that here
} else if (fk < 0) {
// in parent with error from fork
} else {
// in parent with no error so fk = pid of child
}
close(new_stdin); // we don't need this anymore
dup2
дублирует первый аргумент дескриптора файла как второй (закрывая второй перед тем, как сделать это, если он был открыт для текущего процесса).
fork
создает дубликат текущего процесса. execl
- это одна из функций семейства exec
, которые используют системный вызов execve
для замены текущей программы другой программой. Комбинации fork
и exec
- это то, как программы обычно запускаются (даже если они скрыты в других функциях).
В приведенном выше примере мы могли бы запустить новую программу с установленным для stdin концом чтения канала, tty (последовательный порт / TeleTYpe) или несколькими другими вещами. Некоторые из них имеют имена, присутствующие в файловой системе, а другие - нет (например, некоторые каналы и сокеты, хотя некоторые имеют имена в файловой системе).
Linux делает /proc/self/fd/0
символической ссылкой на файл, открытый как 0
в текущем процессе. /proc/%i/fd/0
, pid
будет представлять символическую ссылку на то же самое для произвольного pid (ID процесса) с использованием синтаксиса printf
. Эти символические ссылки часто используются для поиска реального файла в файловой системе (с использованием системного вызова readlink), но если файл фактически не существует в файловой системе, то данные ссылки (что обычно называется именем файла) вместо этого являются просто строкой это немного говорит о файле.
Здесь я должен указать, что файл, на который ссылается stdin (fd 0), даже если он находится в файловой системе, может не иметь только одного имени. У него может быть более одной жесткой ссылки, поэтому у него будет более одного имени - и каждое из них будет таким же именем, как и любая другая жесткая ссылка. Кроме того, он может вообще не иметь имени, если все его жесткие ссылки были unlinked
с момента его открытия, хотя его данные будут оставаться на диске до тех пор, пока все дескрипторы открытого файла для него не будут закрыты.
Если вам на самом деле не нужно знать, где она находится в файловой системе, а просто хотите получить информацию об этом, вы можете использовать системный вызов fstat
. Это похоже на stat
системный вызов и утилиту командной строки, за исключением уже открытых файлов.
Все, что я сказал здесь о stdin
(fd 0), должно быть применимо к stdout (fd 1) и stderr (fd 2) за исключением того, что они оба будут записываемыми, а не читаемыми.
Если вы хотите узнать больше о любой из упомянутых мной функций, обязательно посмотрите их на страницах руководства, набрав:
man fork
в командной строке. Большинство функций, о которых я упоминал, находятся в разделе 2 справочных страниц, но одна или две могут быть в разделе 1, поэтому man 2 fork
также будет работать и может быть полезно, когда инструмент командной строки имеет то же имя, что и функция.