Проблема с zenity и printf (C stdio) [duplicate]

Вы должны установить git-it, прежде чем сможете использовать его в качестве команды. git-он не устанавливается, когда вы устанавливаете Github для окон. Используйте это для установки git-it

npm install -g git-it

и попробуйте.

26
задан Nicholas Wilson 18 December 2012 в 21:17
поделиться

3 ответа

Промывка для stdout определяется его буферизацией. Буферизация может быть настроена на три режима: _IOFBF (полная буферизация: ждет, когда возможно fflush()), _IOLBF (буферизация строк: триггеры новой строки запускают автоматический сброс) и _IONBF (всегда используется прямая запись). «Поддержка этих характеристик определяется реализацией и может быть затронута функциями setbuf() и setvbuf()». [C99: 7.19.3.3]

«При запуске программы три текстовых потока предварительно заданы и их явно не нужно открывать - стандартный ввод (для чтения обычного ввода), стандартный вывод (для записи обычного вывода) и стандартная ошибка (для записи диагностического вывода). Как первоначально было открыто, стандартный поток ошибок не полностью буферизирован, стандартные входные и стандартные выходные потоки полностью буферизованы тогда и только тогда, когда можно определить поток, чтобы не ссылаться на интерактивное устройство ». [C99: 7.19.3.7]

Объяснение наблюдаемого поведения

Итак, происходит то, что реализация делает что-то специфичное для платформы, чтобы решить, будет ли stdout буферизация. В большинстве реализаций libc этот тест выполняется при первом использовании потока.

  1. Поведение # 1 легко объясняется: когда поток предназначен для интерактивного устройства, он буферизируется по строке, а printf() автоматически сбрасывается.
  2. Ожидается также случай # 2: при перенаправлении в файл поток полностью буферизируется и не будет очищаться, кроме как с помощью fflush(), если вы не напишите gobloads of данные к нему.
  3. Наконец, мы понимаем случай # 3 тоже для реализаций, которые выполняют только проверку на базовом fd один раз. Поскольку мы принудительно инициализировали буфер stdout в первом printf(), stdout получил режим буферизации строк. Когда мы поменяем файл fd на файл, он по-прежнему буферизируется, поэтому данные автоматически сбрасываются.

Некоторые фактические реализации

Каждый libc имеет широту в как он интерпретирует эти требования, поскольку C99 не указывает, что такое «интерактивное устройство», а также запись stdio в POSIX расширяется (за исключением того, что stderr будет открыт для чтения).

  1. Glibc. См. filedoalloc.c: L111 . Здесь мы используем stat() для проверки, является ли fd tty, и соответственно настройте режим буферизации. (Это вызвано из fileops.c.) stdout изначально имеет нулевой буфер и выделяется при первом использовании потока на основе характеристик fd 1.
  2. BSD libc. Очень похожий, но гораздо более чистый код для подражания! См. эту строку в makebuf.c
33
ответ дан cnst 19 August 2018 в 01:21
поделиться
  • 1
    Спасибо за ваше предложение по проверке ошибок и устранению утечек. Но я все еще не понимаю, зачем мне здесь флешивать. И почему печать какого-либо сообщения перед перенаправлением может решить проблему. – Patrick 18 December 2012 в 16:05
  • 2
    @Patrick А, я вижу. В этом случае обход этой проблемы: stackoverflow.com/questions/1716296/… – Nicholas Wilson 18 December 2012 в 16:15
  • 3
    Спасибо за Ваш ответ. Но у меня есть & quot;\n & quot; в моем коде, если он запускает флеш? – Patrick 18 December 2012 в 16:21
  • 4
    Хорошо, последний ответ! fsync, fstat, ftruncate и т. д. - это одно семейство функций (в разделе 2); полностью не связан с fopen, fprintf, fflush (раздел 3). fsync находится в ядре и ничего не знает о буферах stdio от libc, которые находятся в вашем приложении. – Nicholas Wilson 19 December 2012 в 10:49
  • 5
    Я получаю это сейчас. close - это системная функция, она также не знает о libc-буфере. – Patrick 21 December 2012 в 13:41

Неправильно сочетаются буферизованные и небуферизованные функции ввода-вывода. Такая комбинация должна выполняться очень тщательно, особенно когда код должен быть переносимым. (и плохо писать неуправляемый код ...) Конечно, лучше избегать объединения буферизованного и небуферизованного ввода-вывода в один и тот же файловый дескриптор.

Буферизованный IO: fprintf(), fopen(), fclose(), freopen() ...

Небуферизованный IO: write(), open(), close(), dup() ...

Когда вы используете dup2() для перенаправление stdout. Функция не знает буфер, который был заполнен fprintf(). Поэтому, когда dup2() закрывает старый дескриптор 1, он не очищает буфер и содержимое может быть сброшено на другой выход. В вашем случае 2a оно было отправлено на /dev/null.

Решение

В вашем случае лучше использовать freopen() вместо dup2(). Это решает все ваши проблемы:

  1. Сбрасывает буферы исходного потока FILE. (случай 2a)
  2. Он устанавливает режим буферизации в соответствии с вновь открытым файлом. (случай 3)

Вот правильная реализация вашей функции:

void RedirectStdout2File(const char* log_path) {
    if(freopen(log_path, "a+", stdout) == NULL) err(EXIT_FAILURE, NULL);
}

К сожалению, с буферизованным IO вы не можете напрямую устанавливать разрешения для вновь созданного файла. Вы должны использовать другие вызовы для изменения разрешений или использовать неперехваченные расширения glibc. См. fopen() man page .

3
ответ дан pabouk 19 August 2018 в 01:21
поделиться

Вы не должны закрывать дескриптор файла, поэтому удалите close(fd) и закройте stdout_bak_fd, если вы хотите, чтобы сообщение печаталось только в файле.

0
ответ дан usain 19 August 2018 в 01:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: