我有一个接受字符串的函数,即:
void log_out(char *);
Run Code Online (Sandbox Code Playgroud)
在调用它时,我需要动态创建一个格式化的字符串,如:
int i = 1;
log_out("some text %d", i);
Run Code Online (Sandbox Code Playgroud)
我如何在ANSI C中执行此操作?
只是,因为sprintf()返回一个int,这意味着我必须编写至少3个命令,如:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Run Code Online (Sandbox Code Playgroud)
有什么方法可以缩短这个吗?
aka*_*ppa 84
使用sprintf.
int sprintf ( char * str, const char * format, ... );
Run Code Online (Sandbox Code Playgroud)
将格式化数据写入字符串如果在printf上使用了格式,则使用与打印时相同的文本组成一个字符串,但不是打印,而是将内容作为C字符串存储在str指向的缓冲区中.
缓冲区的大小应足够大,以包含整个结果字符串(有关更安全的版本,请参阅snprintf).
在内容之后自动附加终止空字符.
在format参数之后,该函数至少需要格式化所需的其他参数.
str
Run Code Online (Sandbox Code Playgroud)
指向存储结果C字符串的缓冲区的指针.缓冲区应足够大以包含结果字符串.
format
Run Code Online (Sandbox Code Playgroud)
包含格式字符串的C字符串,其格式与printf中的格式相同(有关详细信息,请参阅printf).
... (additional arguments)
Run Code Online (Sandbox Code Playgroud)
根据格式字符串,该函数可能需要一系列附加参数,每个参数包含一个值,用于替换格式字符串中的格式说明符(或指向存储位置的指针,用于n).这些参数应至少与格式说明符中指定的值的数量一样多.函数忽略其他参数.
// Allocates storage
char *hello_world = (char*)malloc(13 * sizeof(char));
// Prints "Hello world!" on hello_world
sprintf(hello_world, "%s %s!", "Hello" "world");
Run Code Online (Sandbox Code Playgroud)
cma*_*ter 13
如果您有一个POSIX-2008兼容系统(任何现代Linux),您可以使用安全便捷的asprintf()功能:它将malloc()为您提供足够的内存,您无需担心最大字符串大小.像这样使用它:
char* string;
if(0 > asprintf(&string, "Formatting a number: %d\n", 42)) return error;
log_out(string);
free(string);
Run Code Online (Sandbox Code Playgroud)
这是您以安全的方式构建字符串的最小努力.sprintf()您在问题中提供的代码存在严重缺陷:
指针后面没有分配的内存.您正在将字符串写入内存中的随机位置!
即使你写过
char s[42];
Run Code Online (Sandbox Code Playgroud)
你会陷入深深的麻烦,因为你无法知道括号中的数字.
即使您使用了"安全"变体snprintf(),您仍然会遇到字符串被截断的危险.写入日志文件时,这是一个相对较小的问题,但它有可能准确地切断本来有用的信息.此外,它将切断尾随的结束字符,将下一个日志行粘贴到未成功写入的行的末尾.
如果你尝试在所有情况下使用组合malloc()和snprintf()产生正确的行为,你最终得到的代码大约是我给出的两倍asprintf(),并且基本上重新编程了它的功能asprintf().
如果你正在寻找提供的包装log_out(),可以采取一个printf()风格的参数列表本身,你可以使用变种vasprintf(),这需要va_list作为参数.这是一个非常安全的包装器实现:
//Tell gcc that we are defining a printf-style function so that it can do type checking.
//Obviously, this should go into a header.
void log_out_wrapper(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void log_out_wrapper(const char *format, ...) {
char* string;
va_list args;
va_start(args, format);
if(0 > vasprintf(&string, format, args)) string = NULL; //this is for logging, so failed allocation is not fatal
va_end(args);
if(string) {
log_out(string);
free(string);
} else {
log_out("Error while logging a message: Memory allocation failed.\n");
}
}
Run Code Online (Sandbox Code Playgroud)
Mic*_*urr 11
听起来我希望能够轻松地将使用printf样式格式创建的字符串传递给您已经拥有的带有简单字符串的函数.您可以使用stdarg.h工具创建包装函数vsnprintf()(根据您的编译器/平台,可能不是很容易获得):
#include <stdarg.h>
#include <stdio.h>
// a function that accepts a string:
void foo( char* s);
// You'd like to call a function that takes a format string
// and then calls foo():
void foofmt( char* fmt, ...)
{
char buf[100]; // this should really be sized appropriately
// possibly in response to a call to vsnprintf()
va_list vl;
va_start(vl, fmt);
vsnprintf( buf, sizeof( buf), fmt, vl);
va_end( vl);
foo( buf);
}
int main()
{
int val = 42;
foofmt( "Some value: %d\n", val);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于那些没有提供一系列snprintf()例程的良好实现(或任何实现)的平台,我成功地使用了snprintf()Holger Weiss 的近公共域.