Использование sprintf без выделенного вручную буфера

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

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

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

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

Обновлено: хотя sprintf - это операция C, я ищу решения типа C++ (если они есть!), Чтобы получить такое поведение ...

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
7 017
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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

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

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

доступ к файлам намного медленнее, чем доступ к памяти. Это одна из причин, почему промежуточный спринт - неплохая идея.

xtofl 17.11.2008 13:45

Большую часть этого преимущества можно получить, если буферизовать файл, если это возможно. По-прежнему есть накладные расходы, но, по крайней мере, вы не попадаете на диск.

Steve Jessop 17.11.2008 19:22

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

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

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

Можно защититься от переполнения буфера с помощью vanilla sprintf (), например sprintf (buf, "%. * s", buf_size - 1, input_string); Но это работает только для известных строк фиксированного формата.

finnw 17.09.2009 14:22
Ответ принят как подходящий

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

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

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

Jonathan Leffler 17.11.2008 10:37

-1 для второго предложения (удвоение размера буфера. Поскольку вы не знаете максимальную длину строки, вы не можете гарантировать, что она не переполнится, даже если вы умножите ее на миллиард).

finnw 17.09.2009 14:16

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

Пожалуйста, отметьте доступность этой функции для разных систем, потому что это не стандартная библиотека C lib или POSIX.

qrdl 17.11.2008 10:17

В основном это Linux - вероятно, тоже BSD. Также существует vasprintf ().

Jonathan Leffler 17.11.2008 10:38

Ах да, извините за это ... OP не упомянул, какая платформа, поэтому я просто выбросил ее туда. Его можно найти в Linux, BSD и Mac OS X ... теперь это стандартная часть библиотеки gnuc.

Jason Coco 17.11.2008 11:04

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

length = snprintf(NULL, ...);
str = malloc(length+1);
snprintf(str, ...);

Если вы используете C99, вы также можете просто использовать массив переменной длины, поэтому вместо mallocing str просто объявите его как «char str [length + 1];» после вызова snprintf. Тогда не нужно освобождать его, так как он находится в стеке.

Ben Combee 17.11.2008 11:36

Если вы используете среду выполнения MSVC, вы обнаружите, что snprintf возвращает отрицательное значение вместо требуемой длины. поэтому, если вам нужна требуемая длина в MSVC, вам нужно будет использовать другую функцию, _vscprintf [msdn.microsoft.com/en-us/library/w05tbk72.aspx]

Hasturkun 17.11.2008 12:17

Другие вопросы по теме