Перенаправление стандартного ввода-вывода в Windows немного сложнее из-за отсутствия надлежащего интерфейса для сопоставления произвольных дескрипторов файлов Win32 и файловых дескрипторов / потоков более высокого уровня.
На самом деле в Windows есть три разных уровня ввода / вывода:
- Стандартный? Потоки ввода / вывода C (они используются
printf
, scanf
, ...)
- дескрипторы ввода / вывода POSIX (это целые числа, используемые
read
, write
, ...)
- дескрипторы ввода / вывода Win32 API (используются
ReadFile
, WriteFile
, ...)
Перенаправление потоков C
Для перенаправления потоков C вы можете использовать freopen
. Например, вы можете перенаправить C stdout
, используя:
freopen("log.txt", "w", stdout);
Это перенаправление обычно не перенаправляет ввод / вывод, выполняемый API POSIX или Win32 (они все равно будут читать / записывать присоединенную консоль, если таковая имеется). Кроме того, это перенаправление не будет наследоваться дочерними процессами. (В POSIX-совместимых / не-Windows системах обычно POSIX API также является системным API, а C API реализован поверх POSIX API. В этих случаях достаточно freopen
.)
Перенаправление дескрипторов ввода / вывода POSIX
Чтобы перенаправить ввод / вывод на уровне API POSIX, вы можете использовать dup2
. Например, вы можете переназначить дескриптор файла STDOUT_FILENO
для перенаправления stdout
, что-то вроде:
int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);
К сожалению, в Windows даже перенаправление на уровне API POSIX не гарантирует перенаправление ни на уровне C, ни на уровне Win32 API . Будет ли это работать или нет, зависит от усилий, приложенных в реализации библиотеки C для сопоставления между дескрипторами файлов POSIX и дескрипторами файлов Win32 (при условии, что библиотека времени выполнения C использует слоистый ввод-вывод поверх POSIX для начала) , Также нет гарантии, что это перенаправление будет унаследовано порожденными детьми.
Перенаправление ввода-вывода Std в Windows!
Чтобы правильно перенаправить ввод / вывод в Windows, вы должны перенаправить на самый низкий уровень (т. Е. Уровень Win32 API) и исправить связь на более высоких уровнях следующим образом:
- Назначьте новый дескриптор, позвонив по номеру
CreateFile
.
- Назначьте этот новый дескриптор нужному стандартному устройству ввода-вывода, используя
SetStdHandle
.
- Свяжите этот новый дескриптор с соответствующим дескриптором файла C std, используя
_open_osfhandle
(возвращает номер дескриптора файла).
- Перенаправить возвращенный дескриптор файла, используя метод
dup2
, описанный выше.
Вот пример фрагмента для перенаправления stdout
:
HANDLE new_stdout = CreateFileA("log.txt", ...);
SetStdHandle(STD_OUTPUT_HANDLE, new_stdout);
int fd = _open_osfhandle(new_stdout, O_WRONLY|O_TEXT);
dup2(fd, STDOUT_FILENO);
close(fd);
P.S. Если вы можете обойтись без перенаправления ввода-вывода внутри программы, то вы можете просто использовать перенаправление консоли ввода-вывода в командной строке, используя крошечный пакетный файл:
@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"