У меня есть функция, которая принимает строку, а именно:
void log_out(char *);
При его вызове мне нужно на лету создать отформатированную строку, например:
int i = 1;
log_out("some text %d", i);
Как мне это сделать в ANSI C?
Только, поскольку sprintf()
возвращает int, это означает, что мне нужно написать как минимум 3 команды, например:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Есть способ сократить это?
Ответы:
Используйте sprintf .
Параметры:
Пример:
источник
Если у вас есть система, совместимая с POSIX-2008 (любой современный Linux), вы можете использовать безопасную и удобную
asprintf()
функцию: у вас будетmalloc()
достаточно памяти, вам не нужно беспокоиться о максимальном размере строки. Используйте это так:Это минимальные усилия, которые вы можете приложить, чтобы построить строку безопасным способом.
sprintf()
Код вы дали в вопросе глубоко испорчен:За указателем нет выделенной памяти. Вы записываете строку в случайное место в памяти!
Даже если бы ты написал
у вас будут большие проблемы, потому что вы не знаете, какое число поместить в скобки.
Даже если бы вы использовали «безопасный» вариант
snprintf()
, вы все равно столкнетесь с опасностью усечения ваших строк. При записи в файл журнала это относительно несущественная проблема, но она может отсечь именно ту информацию, которая была бы полезной. Кроме того, он обрежет завершающий символ конечной строки, приклеивая следующую строку журнала к концу неудачно написанной строки.Если вы попытаетесь использовать сочетание
malloc()
иsnprintf()
для обеспечения правильного поведения во всех случаях, вы получите примерно в два раза больше кода, чем я далasprintf()
, и в основном перепрограммируете функциональностьasprintf()
.Если вы хотите предоставить оболочку,
log_out()
которая может приниматьprintf()
сам список параметров стиля, вы можете использовать вариант,vasprintf()
который принимаетva_list
в качестве аргумента. Вот совершенно безопасная реализация такой оболочки:источник
asprintf()
это не входит ни в стандарт C 2011, ни в POSIX, ни даже в POSIX 2008 или 2013. Это часть TR 27431-2: см. Используете ли вы «безопасные» функции TR 24731?Мне кажется, вы хотите иметь возможность легко передавать строку, созданную с использованием форматирования в стиле printf, в функцию, которая у вас уже есть, которая принимает простую строку. Вы можете создать функцию-оболочку, используя
stdarg.h
средства иvsnprintf()
(которые могут быть недоступны, в зависимости от вашего компилятора / платформы):Для платформ, которые не обеспечивают хорошую реализацию (или любую реализацию)
snprintf()
семейства подпрограмм, я успешно использовал почти общественное достояниеsnprintf()
от Holger Weiss .источник
Если у вас есть код
log_out()
, перепишите его. Скорее всего, вы сможете:Если требуется дополнительная информация для регистрации, ее можно распечатать до или после отображаемого сообщения. Это экономит выделение памяти и сомнительные размеры буфера и так далее и так далее. Вероятно, вам нужно инициализировать
logfp
нулевое значение (нулевой указатель) и проверить, является ли он нулевым, и при необходимости открыть файл журнала, но код в существующемlog_out()
все равно должен иметь дело с этим.Преимущество этого решения в том, что вы можете просто назвать его, как если бы это был вариант
printf()
; действительно, это второстепенный вариантprintf()
.Если у вас нет кода
log_out()
, подумайте, можете ли вы заменить его вариантом, подобным описанному выше. Возможность использования того же имени будет зависеть от среды вашего приложения и конечного источника текущейlog_out()
функции. Если он находится в том же объектном файле, что и другая незаменимая функция, вам придется использовать новое имя. Если вы не можете понять, как его точно воспроизвести, вам придется использовать какой-то вариант, аналогичный приведенным в других ответах, который выделяет соответствующий объем памяти.Очевидно, что теперь вы вызываете
log_out_wrapper()
вместоlog_out()
- но выделение памяти и так далее выполняется один раз. Я оставляю за собой право перераспределить пространство на один ненужный байт - я дважды не проверял,vsnprintf()
включает ли длина, возвращаемая с помощью, завершающий нуль или нет.источник
Не используйте sprintf.
Это переполнит ваш String-Buffer и приведет к сбою вашей программы.
Всегда используйте snprintf
источник
Я этого не делал, поэтому просто укажу правильный ответ.
C имеет положения для функций, которые принимают неопределенное количество операндов, используя
<stdarg.h>
заголовок. Вы можете определить свою функцию какvoid log_out(const char *fmt, ...);
, и получитьva_list
внутри функции. Затем вы можете выделить память и вызватьvsprintf()
выделенную память, отформатировать иva_list
.В качестве альтернативы вы можете использовать это для написания функции, аналогичной
sprintf()
той, которая выделяла бы память и возвращала отформатированную строку, генерируя ее более или менее, как указано выше. Это будет утечка памяти, но если вы просто выходите из системы, это может не иметь значения.источник
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html дает следующий пример для печати на stderr. Вы можете изменить его, чтобы вместо этого использовать функцию журнала:
Вместо vfprintf вам нужно будет использовать vsprintf, где вам нужно предоставить соответствующий буфер для печати.
источник