Существует ли универсальная процедура printf-ish, определенная в каком-либо стандарте C - PullRequest
2 голосов
/ 15 марта 2011

Во многих C-библиотеках есть процедура в стиле printf, которая выглядит примерно так:

int __vgprintf(void *info, (void)(*print_function(void*, char)), const char *format, va_list params);

, который отформатирует предоставленную строку и вызовет функцию print_function с переданным информационным значением и каждым символом в последовательности. Функция, подобная fprintf, передает __vgprintf переданный параметр файла и указатель на функцию, которая преобразует свой void * в FILE * и выводит переданный символ в этот файл. Функция наподобие snprintf создаст структуру, содержащую символ * и длину, и передаст адрес этой структуры функции, которая будет выводить каждый символ в последовательности, если позволяет пространство.

Существует ли какой-либо стандарт для такой функции, который можно использовать, например, если кто-то хотел функцию для вывода произвольного формата на порт TCP? Обычный подход состоит в том, чтобы выделить буфер, который, как мы надеемся, достаточно велик, использовать snprintf, чтобы поместить туда данные, а затем вывести данные из буфера. Впрочем, было бы чище, если бы существовал стандартный способ указать, что средство форматирования печати должно вызывать пользовательскую подпрограмму с каждым символом.

Ответы [ 4 ]

2 голосов
/ 15 марта 2011

Существует ли какой-либо стандарт для такой функции, который можно использовать, если, например, требуется, чтобы функция выводила произвольный формат на порт TCP?

Вы можете заключить дескриптор файлаили сокет в FILE*, используя fdopen() и передайте его в fprintf().Однако это не работает с неблокирующими сокетами.

Сначала форматирование в буфере дает вам гораздо большую гибкость и возможность использовать его с неблокирующими сокетами.

2 голосов
/ 15 марта 2011

open_memstream является стандартным в POSIX, а может быть стандартизирован как часть языка C в следующем стандарте C1x.Однако это не предлагает вам произвольный обратный вызов;он требует, чтобы весь вывод помещался в память, так что на самом деле это не лучше, чем использование snprintf (возможно, обернутое функцией, автоматически распределяющей буфер).

В системах POSIX одно из решений заключается в созданииканал в новый поток, а затем используйте dprintf (или fdopen и fprintf) для записи в него.Поток получит входные данные на другом конце канала и может обработать его так, как ему нравится.Конечно, это немного медленно (по крайней мере, пара системных вызовов каждый раз, когда вывод сбрасывается, и, возможно, переключение контекста, если у вас слишком мало ядер), но это делает то, что вы хотите.Тот же подход будет работать в любой системе с конвейерами, потоками и эквивалентом fdopen или dprintf, поэтому вы должны иметь возможность заставить его работать и в Windows, если это необходимо.

Другой подход заключается виспользуйте tmpfile, fprintf и fread (все стандартные C).Хорошая реализация tmpfile может даже создать виртуальный файл в памяти и отложить любое фактическое создание файла до тех пор, пока не будет вызван fileno или размер файла не превысит определенный предел.

Редактировать: После перечитывания вопроса кажется, что OP просто нужно использовать fprintf с сокетами.В этом случае fdopen / fprintf или dprintf выполняет задачу напрямую.

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

Нестандартно, но посмотрите на fopencookie в Linux и funopen в BSD. Может быть возможно обернуть их в стандартный API из вашего приложения, поскольку они очень похожи. Я полагаю, что Cygwin и Mac OS X также поддерживают хотя бы одну из них.

Обе функции позволяют создавать FILE * с указателями на функции для чтения, записи, поиска и закрытия потока. После создания вы можете fprintf в поток.

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

Я серьезно сомневаюсь, что есть такая стандартная функция, но вы, конечно, можете создать свою собственную реализацию, чтобы попробовать и подражать ей. К сожалению.

...