有谁知道将printf样式函数的输出重定向到字符串的安全方法吗?显而易见的方式会导致缓冲区溢出。安全printf到字符串的最佳方法?
喜欢的东西:
string s;
output.beginRedirect(s); // redirect output to s
... output.print("%s%d", foo, bar);
output.endRedirect();
我认为这个问题是一样的问,“有多少个字符将打印生产?” 想法?
有谁知道将printf样式函数的输出重定向到字符串的安全方法吗?显而易见的方式会导致缓冲区溢出。安全printf到字符串的最佳方法?
喜欢的东西:
string s;
output.beginRedirect(s); // redirect output to s
... output.print("%s%d", foo, bar);
output.endRedirect();
我认为这个问题是一样的问,“有多少个字符将打印生产?” 想法?
This StackOverflow question也有类似的讨论。同样在那个问题中,我提出了我最喜欢的解决方案,一个“格式”函数,它接受printf的相同参数并返回一个std :: string。
的snprintf()
功能打印成字符串,但只有尽可能给它的长度。
可能是你在找什么...
比我快。这是老派的做法。 – dmckee 2009-01-12 18:11:18
您可以使用不需要长度的sprintf。此外,这不会与字符串,因为他问... – 2009-01-12 18:12:41
您可以使用:
std::snprintf
,如果你是一个char *工作
std::stringstream
,如果你想使用字符串(不相同作为printf,但将允许您使用普通流功能轻松操纵字符串)。
boost::format
如果你想要一个类似于printf的函数来处理流。 (根据jalf的评论)
在C99中,您有snprintf函数,它将缓冲区的大小作为参数。 GNU C库有asprintf,为你分配一个缓冲区。不过,对于C++来说,你可能会更好地使用iostream。
Wikipedia有更多信息。
老同学:
snprintf()
允许你把书面的数量限制,并返回实际写的大小和
asprintf()
分配(与malloc()
)足够的缓冲,然后成为您的问题free()
。 `asprintf是一个现在在BSD libc中重新实现的GNU libc函数。
由于您已将此标记为C++(而不仅仅是C),因此我会指出在C++中执行此类操作的典型方法是使用stringstream而不是printf系列。无需担心字符串流的缓冲区溢出问题。
Boost Format库也可用,如果你喜欢printf风格的格式化字符串,但想要更安全的话。
snprintf()返回写入整个字符串所需的字节数。 所以,作为一个小小的例子:
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char* buf = 0;
size_t bufsize = 0;
size_t sz;
const char* format="%s and %s.";
const char* str_1 ="string 1";
const char* str_2 ="string 2";
sz = snprintf(buf, bufsize, format, str_1, str_2);
printf("The buffer needs to be %d bytes.\n", sz);
buf=malloc(sz+1);
if(!buf) {
printf("Can't allocate buffer!\n");
return 1;
}
bufsize = sz+1;
buf[bufsize-1] = '\0';
sz = snprintf(buf, bufsize, format, str_1, str_2);
printf("Filled buffer with %d bytes.\n", sz);
printf("The buffer contains:\n'%s'\n", buf);
return 0;
}
输出:
The buffer needs to be 22 bytes.
Filled buffer with 22 bytes.
The buffer contains:
'string 1 and string 2.'
在Windows上:
StringCchPrintf
StringCbPrintf
从strsafe.h/lib
。
我发现printf格式比流更容易使用和使用。另一方面,我也很喜欢std :: string。解决方案是使用sprintf,但不能处理任意的缓冲区大小。
我发现我需要处理常见的情况(比如,缓冲区限制为256个字符),而不是 开销,并且安全地处理大型缓冲区。为此,我有一个256字节的缓冲区,作为成员放在我的课程中,我使用snprinf,传递该缓冲区及其大小。如果snprintf成功,我可以立即重新格式化字符串。如果失败,我分配缓冲区并再次调用snprinf。该缓冲区在类的析构函数中被释放。
The fmt library提供fmt::sprintf
功能执行printf的兼容格式(包括根据POSIX specification位置参数),并返回其结果作为std::string
:
std::string s = fmt::sprintf("%s%d", foo, bar);
声明:我此库的作者。
不适用于任何其他符合标准的实现,所以yuck。 – Bklyn 2009-01-12 22:18:07
此外,唯一的区别是,如果“安全”crt检测到某些未定义的行为,它会自行崩溃。这并不能绕过他遇到的问题。 – 2014-08-19 19:47:48