Восстановление стандартного вывода после перенаправления через freopen () - PullRequest
0 голосов
/ 12 мая 2019

Это продолжение Как записать вывод printf? - в частности, ответ jxh.

У меня такая же проблема с кодом в ответе, что Виестурсбыло в 2018 году. Ему предложили открыть новый вопрос, который, по его словам, его учетная запись не разрешила, поэтому я открываю новый вопрос в том же духе.

На этот ответ,в 2012 году автор оригинального опроса сказал, что это сработало.В 2018 году Виестурс сказал, что после запуска кода дальнейший вывод не появился ни на консоли, ни в перенаправленном файле.

У меня такая же проблема.Используя приведенный ниже код, this shouldn't be redirected\n не отображается на консоли и не отображается в перенаправленном файле.Перенаправленный файл содержит только первую напечатанную строку.

Я использую gcc 8.3.0, а также пробовал gcc 6.5.0.glibc 2.29.

Обратите внимание, что я НЕ хочу freopen с "CON" впоследствии.Даже если это сработает, я хочу сохранить исходный стандартный вывод, поскольку он сам может быть перенаправлением.(Хотя в моем тестировании это была только консоль.)

Либо: в ответе jxh есть ошибка;Я делаю ту же ошибку, что был Виестурс;или (насколько я понимаю) ошибка была введена (или исправлена) где-то раньше, чем gcc 6.5.0 или glibc 2.29.

redirected.c

#include <unistd.h>
#include <stdio.h>

void funcB() {
   printf("this should be redirected\n");
   fflush(stdout);
}

int main() {
   int stdout_fd = dup(STDOUT_FILENO);
   freopen("/tmp/redirected", "w", stdout);
   funcB();
   fclose(stdout);
   dup2(stdout_fd, STDOUT_FILENO);
   stdout = fdopen(STDOUT_FILENO, "w");
   close(stdout_fd);

   printf("this shouldn't be redirected\n");
   fflush(stdout); // shouldn't make a difference if this is here
}

Выход:

$ gcc redirected.c
$ ./a.out
<THERE IS NO OUTPUT>
$ cat /tmp/redirected
this should be redirected

Ответы [ 2 ]

3 голосов
/ 12 мая 2019

Нет правильного решения, это может включать:

  • присвоение stdout, потому что stdout не является переменной / lvalue. Это макрос, который расширяется до выражения типа FILE *. Если это также lvalue, это подробности реализации для любой конкретной реализации, а не часть языка.
  • fclose(stdout), поскольку после fclose(stdout) любое дальнейшее использование stdout в любом месте программы, неявное (например, printf) или явное, в течение остальной части времени выполнения вызывает неопределенное поведение.

Хорошее решение также не включает freopen, хотя вы могли бы сделать эту работу. Вместо этого просто используйте dup2, с fflush. Этот ответ (от меня) объясняет, как это сделать:

https://stackoverflow.com/a/4832902/379897

Вместо "/dev/null".

замените файл, который вы хотите направить в.
2 голосов
/ 12 мая 2019

Не гарантируется, что существует какой-либо способ повторно подключить stdin к исходному файлу после переназначения его через freopen().В частности, не указано, расширяется ли макрос stdin до модифицируемого lvalue, тем более что эффект, присваиваемый результату, имеет.Это на самом деле причина freopen() во-первых.

Метод, который вы пытаетесь использовать, правдоподобен, но, опять же, не гарантированно сработает, и я наблюдаю то же поведение, которое вы описываете для себя.Возможно, ваша версия printf и моя оптимизированы с идентификатором stdout, так что присвоение нового значения этому символу не влияет на назначение вывода этой функции, которое вы закрываете перед печатью.

Вы используете интерфейсы POSIX (dup и dup2), и в реализации, соответствующей POSIX, наиболее вероятный подход к работе - избегать закрытия stdin, а вместо этого переопределять файл, в который он записывает, с помощью dup2() только.В этом случае вы должны быть осторожны с fflush() перед таким обменом, что-то вроде этого:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void funcB() {
   printf("this should be redirected\n");
   fflush(stdout);
}

int main() {
   int stdout_fd = dup(STDOUT_FILENO);
   int rd_fileno = open("/tmp/redirected", O_WRONLY | O_CREAT | O_TRUNC, 0600);
   dup2(rd_fileno, STDOUT_FILENO);
   funcB();
   fflush(stdout);
   dup2(stdout_fd, STDOUT_FILENO);
   close(stdout_fd);

   printf("this shouldn't be redirected\n");
   fflush(stdout); // shouldn't make a difference if this is here
}

Эта версия работает для меня и основана на той же основе, что и перенаправление, как правило, в POSIX.В частности, обратите внимание, что stdout никогда не закрывается (за исключением автоматического завершения программы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...