Можно ли узнать, сколько байтов было напечатано в файловом потоке, например при стандартном выводе? - PullRequest
3 голосов
/ 12 марта 2011

Может ли вызывающая программа на C узнать, сколько байт она напечатала в файловом потоке, таком как stdout, фактически не считая и не суммируя возвращаемые значения printf?

Я пытаюсь реализовать контроль количества выходных данных программы на С, которая использует библиотеки для печати, но библиотеки не сообщают количество напечатанных данных.

Iменя интересует либо общее решение, либо специфичное для Unix.

Ответы [ 4 ]

1 голос
/ 12 марта 2011

POSIX-специфично: перенаправить stdout в файл, сбросить после того, как все записи завершены, затем проследить за файлом и посмотреть st_size (или использовать команду ls).

Обновление : Вы говорите, что пытаетесь контролировать количество вывода программы. Команда POSIX head сделает это. Если это неудовлетворительно, четко изложите свои требования.

0 голосов
/ 19 марта 2011

printf возвращает количество записанных байтов.

Добавьте их.

0 голосов
/ 19 марта 2011

Это довольно тяжелое решение, но сработает следующее:

  1. Создайте канал, вызвав pipe()
  2. Создайте дочерний процесс
  3. Вparent: перенаправить stdout на сторону записи канала и закрыть сторону чтения (и старую stdout)
  4. В дочернем: продолжить чтение со стороны чтения канала и копироватьданные в унаследованный stdout (который является исходным stdout) - считая его по мере того, как он проходит мимо
  5. В родителе продолжайте записывать в stdout (который теперь является каналом) как обычно
  6. Использование какой-либо формы IPC для передачи результата подсчета от дочернего элемента к родительскому.

По сути, идея состоит в том, чтобы порождать дочерний процесс и передавать весь вывод через него,и пусть дочерний процесс подсчитывает все данные по мере прохождения.

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

Самая сложная часть - это синхронизация, то есть обеспечение того, чтобы в то время, когда ребенок сообщает родителю, сколько данных было написано, он ужеобработал все данные, которые сказал родитель (а в канале, например, ничего не осталось).Насколько это важно, будет зависеть от того, к какой именно цели вы стремитесь - если приблизительное указание - это все, что требуется, тогда вы сможете избежать использования общей памяти для IPC и не выполнять какой-либо явной синхронизации;если итог требуется только в конце, вы можете закрыть stdout от родителя и попросить ребенка указать в общей памяти, когда он получил уведомление eof.

Если вам требуется чащесчитывания, которые должны быть точными, тогда потребуется нечто большее, чем copmlex, но это может быть достигнуто путем разработки какого-либо протокола с использованием сокетов, каналов или даже condvars / semaphores / etc в общей памяти.

0 голосов
/ 12 марта 2011

Не знаю, насколько это надежно, но вы можете использовать ftell на стандартный вывод:

long int start = ftell(stdout);
printf("abcdef\n");
printf("%ld\n", ftell(stdout) - start); // >> 7

EDIT Проверил это в Ubuntu Precise: он не работает, если вывод идет на консоль, но работает, если он перенаправлен в файл.

$ ./a.out 
abcdef
0
$ ./a.out >tt
$ cat tt
abcdef
7
$ echo `./a.out`
abcdef 0
$ echo `cat tt`
abcdef 7
...