LINUX.ORG.RU

printf vs fprintf(stderr)

 , ,


0

2

Всех приветствую!

Задался таким вопросом: а нужно ли городить

 fprintf(stderr, "Error: bla-bla\n");

вместо простого

printf("Error: bla-bla\n");

Ведь результат один и тот же.

Когда необходимо разделять stderr и stdout? Вообще, когда и как может использоваться stderr?

PS Заранее благодарю за ответы.


Ты не знаешь, чем отличаешься stdout от stderr или что? ./myprogram > stdout.log 2>stderr.log - вот пример, где результат будет не один и тот же. Когда необходимо - тебе видней. В целом принято сообщения об ошибках и тп выводить в stderr, а результат программы в stdout. Если тебе так удобней - можешь всё в stdout выводить, ничего страшного от этого не случится.

vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)

Результат не один и тот же, это только в эмуляторе терминала у тебя они с кашу по дефолту. fprintf() лучше, так как при желании и неумолимой необходимости эту кашу вообще можно разгрести.

Идеальный вариант - поуровневое логирование, но с такими вопросами вы ещё «не там» :)

Bfgeshka ★★★★★
()

Стандартный вывод — это вовсе не обязательно вывод в консоль пользователя. Данные, которые программа выводит в стандартный вывод, может быть, например, в каком-то определённом формате, это вообще могут быть не текстовые данные.

Например: cat picture.jpg | wc -c

Здесь программа cat выводит на стандартный вывод содержимое графического файла. Если она будет писать и сообщения об ошибках в стандартный вывод, то получится ерунда.

anarquista ★★★★★
()
#include<stdio.h>

int main ( ) {
    printf( "hello " );
    fprintf( stderr, "HELP!" );
    printf( " world\n" );
    return 0;
}

Результат:

HELP!hello  world

stdout и stderr по разному буферизируются?

Gyros
() автор топика
Ответ на: комментарий от Gyros

Это зависит от реализации стандартной библиотеки. При выводе в консоль стандартный вывод часто буферизируется построчно. Соответственно, стандартный вывод будет напечатан, когда встретится символ «\n».

Для управления буферизацией есть функция setbuf.

anarquista ★★★★★
()
Ответ на: комментарий от Gyros

Двойка обозначает второй дескриптор, то есть стандартный вывод ошибок.

Werenter ★★☆
()
Ответ на: комментарий от Gyros

У программ в юниксе обычно при запуске открыто три файловых дескриптора. 0 это стандартный ввод, 1 это стандартный вывод, 2 это вывод для ошибок. Синтаксис N>file ассоциирует соответствующий вывод с записью в файл с соответствующим названием. Вместо 1> stdout.log можно писать просто > stdout.log. Для перенаправления ввода надо писать < stdin.txt к примеру, тогда стандартный ввод будет считываться не с клавиатуры, а из файла.

Рекомендую почитать какие-нибудь обучающие статьи по bash и в целом по основам UNIX, без этого полного понимания не будет. В двух словах тут всё не распишешь.

vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)

1. stderr не буферизируется, а выводится сразу, тут я думаю все понятно, иногда если ты уже испортил всю память и стек, printf у тебя работать не будет, сброс буфера не совершится, а fprintf stderr имеет шансы на успех.

#include <stdio.h>

int main()
{
	fprintf(stdout, "stdout");
	fprintf(stderr, "stderr");
	for (;;);
}
$ ./a.out 
stderr^C

2. сообщения из stderr видны даже если ты перенаправил stdout в файл, как бонус в итоговом файле у тебя не будут мешаться данные и сообщения, на stdout может подаваться картинка, если вывести в середину что то в stdout то она поломается.

3. если используешь SDL, то можешь изучить эту страницу https://wiki.libsdl.org/SDL2/CategoryLog

MOPKOBKA ★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)

Задался таким вопросом: а нужно ли городить

Да.

Ведь результат один и тот же.

Нет. stderr и stdout разные потоки вывода. Кто-то может логировать ошибки в отдельный файл или передавать в другую программу.

zx_gamer ★★★
()

Нет результат разный. На stdout выходные данные, на stderr сообщения о статусе и ошибках. Если ты запустишь пайплайн foo | bar | baz > out, stdout пойдёт по пайпам и далее в файл, а stderr попадёт тебе в терминал.

anonymous
()
Ответ на: комментарий от urxvt

По умолчанию stderr не должен быть полностью буферизован. То есть он может быть либо вообще не буферизован, либо построчно буферизован. В glibc и musl поток stderr не буферизован.

i-rinat ★★★★★
()

Мало кто знает, но можно писать и так:

./myprogram > stdout.log 2>stderr.log 3>qwerty.log 10>other.log 100>100500.log
stdin, stdout, strerr это просто константы для 0,1,2 никто не мешает делать и так:
write(3, 'Output to qwerty.log\n', len)
write(10, 'Output to other.log\n', len)
write(100, 'Output to 100500.log\n', len)
vitus@xxx:/tmp$ cat test.c
#include <unistd.h>
#include <string.h>

int main() {
        char * str = "test\n";
        write(3, str, strlen(str));
}
vitus@xxx:/tmp$ gcc test.c
vitus@xxx:/tmp$ ./a.out 3>test.log
vitus@xxx:/tmp$ cat test.log
test

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Вроде бы файловых дескрипторов по умолчанию меньше 100. Поэтому write(100, ‘Output to 100500.log\n’, len) может не сработать?

anonymous
()
Ответ на: комментарий от vtVitus

Тогда надо ещё упомянуть и про возможность на лету поменять местами stdout и stderr:

./myprogram 3>&2 2>&1 1>&3
anonymous
()
Ответ на: комментарий от anonymous

А вот ещё:

Следует ли мне перейти на clang?
у меня убунта крайняя если чё.
anonymous
()
Ответ на: комментарий от anonymous

А вот ещё, бл*ть, ещё:

Я попытался скормить этот код GCC, а он выдал портянку...
Следует ли мне перейти на clang?
у меня убунта крайняя если чё.
anonymous
()
Ответ на: комментарий от anonymous

100, если и было то давно, сейчас ulimit -n по умолчанию 1024.

vitus@xxx:/tmp$ cat test.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main() {
        char * str = "test\n";
        write(1024, str, strlen(str));
        return 0;
}
vitus@xxx:/tmp$ gcc test.c
vitus@xxx:/tmp$ ./a.out 1024>test.log
-bash: 1024: Неправильный дескриптор файла
vitus@xxx:/tmp$ ulimit -n
1024
vitus@xxx:/tmp$ ulimit -n 1025
vitus@xxx:/tmp$ ulimit -n
1025
vitus@xxx:/tmp$ ./a.out 1024>test.log
vitus@xxx:/tmp$ cat test.log
test

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)

Всегда разделять ошибки и обычный вывод, выводя ошибки в stderr, является хорошим тоном (за редчайшими исключениями).

ad0c
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.