Использование sprintf без выделенного вручную буфера - PullRequest
7 голосов
/ 17 ноября 2008

В приложении, над которым я работаю, средство ведения журнала использует sprintf для форматирования текста, который записывается в файл. Итак, что-то вроде:

char buffer[512];
sprintf(buffer, ... );

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

Есть ли способ получить поведение sprintf без необходимости вручную распределять память следующим образом?

РЕДАКТИРОВАТЬ: хотя sprintf является операцией C, я ищу решения типа C ++ (если они есть!) Для меня, чтобы получить такое поведение ...

Ответы [ 5 ]

18 голосов
/ 17 ноября 2008

Вы можете использовать asprintf (3) (примечание: нестандартное), которое выделяет буфер для вас, поэтому вам не нужно предварительно выделять его.

10 голосов
/ 17 ноября 2008

Нет, вы не можете использовать sprintf(), чтобы выделить достаточно памяти. Альтернативы включают в себя:

  • используйте snprintf() для усечения сообщения - не полностью решит вашу проблему, но предотвратит проблему переполнения буфера
  • удвоить (или утроить или ...) буфер - если вы не находитесь в стесненных условиях
  • используйте C ++ std::string и ostringstream - но вы потеряете формат printf, вам придется использовать оператор
  • используйте Boost Format , который поставляется с оператором%, похожим на printf
5 голосов
/ 17 ноября 2008

Я также не знаю версию, которая избегает выделения, но если C99 sprintfs разрешает в качестве строки указатель NULL. Не очень эффективно, но это даст вам полную строку (если доступно достаточно памяти) без риска переполнения:

length = snprintf(NULL, ...);
str = malloc(length+1);
snprintf(str, ...);
3 голосов
/ 17 ноября 2008

"средство ведения журнала использует sprintf для форматирования текста, который записывается в файл"

fprintf() не накладывает никаких ограничений по размеру. Если вы можете написать текст непосредственно в файл, сделайте это!

Я предполагаю, что есть некоторый промежуточный шаг обработки, однако. Если вы знаете, сколько места вам нужно, вы можете использовать malloc(), чтобы выделить это место.

Одна из техник, подобных этим, заключается в выделении буфера разумного размера (который будет достаточно большим в 99% случаев), а если он недостаточно велик, разбивайте данные на куски, которые вы обрабатываете один за другим. *

1 голос
/ 17 ноября 2008

В стандартной версии sprintf нет способа предотвратить перезапись данных, переданных в буфер. Это верно независимо от того, была ли память выделена вручную или выделена в стеке.

Чтобы предотвратить перезапись буфера, вам нужно использовать одну из более безопасных версий sprintf, например sprintf_s (только для windows)

http://msdn.microsoft.com/en-us/library/ybk95axf.aspx

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