2009-01-12 27 views
12

有谁知道将printf样式函数的输出重定向到字符串的安全方法吗?显而易见的方式会导致缓冲区溢出。安全printf到字符串的最佳方法?

喜欢的东西:

string s; 
output.beginRedirect(s); // redirect output to s 

... output.print("%s%d", foo, bar); 

output.endRedirect(); 

我认为这个问题是一样的问,“有多少个字符将打印生产?” 想法?

回答

4

This StackOverflow question也有类似的讨论。同样在那个问题中,我提出了我最喜欢的解决方案,一个“格式”函数,它接受printf的相同参数并返回一个std :: string。

0

微软为此推出'safe'crt函数。

你可以使用printf_s()

+2

不适用于任何其他符合标准的实现,所以yuck。 – Bklyn 2009-01-12 22:18:07

+0

此外,唯一的区别是,如果“安全”crt检测到某些未定义的行为,它会自行崩溃。这并不能绕过他遇到的问题。 – 2014-08-19 19:47:48

11

snprintf()功能打印成字符串,但只有尽可能给它的长度。

可能是你在找什么...

+0

比我快。这是老派的做法。 – dmckee 2009-01-12 18:11:18

+0

您可以使用不需要长度的sprintf。此外,这不会与字符串,因为他问... – 2009-01-12 18:12:41

24

您可以使用:

std::snprintf,如果你是一个char *工作

std::stringstream,如果你想使用字符串(不相同作为printf,但将允许您使用普通流功能轻松操纵字符串)。

boost::format如果你想要一个类似于printf的函数来处理流。 (根据jalf的评论)

1

在C99中,您有snprintf函数,它将缓冲区的大小作为参数。 GNU C库有asprintf,为你分配一个缓冲区。不过,对于C++来说,你可能会更好地使用iostream。

Wikipedia有更多信息。

4

老同学:

snprintf() 

允许你把书面的数量限制,并返回实际写的大小和

asprintf() 

分配(与malloc())足够的缓冲,然后成为您的问题free()。 `asprintf是一个现在在BSD libc中重新实现的GNU libc函数。

6

由于您已将此标记为C++(而不仅仅是C),因此我会指出在C++中执行此类操作的典型方法是使用stringstream而不是printf系列。无需担心字符串流的缓冲区溢出问题。

Boost Format库也可用,如果你喜欢printf风格的格式化字符串,但想要更安全的话。

3

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.' 
0

在Windows上:

StringCchPrintf 
StringCbPrintf 

strsafe.h/lib

1

我发现printf格式比流更容易使用和使用。另一方面,我也很喜欢std :: string。解决方案是使用sprintf,但不能处理任意的缓冲区大小。

我发现我需要处理常见的情况(比如,缓冲区限制为256个字符),而不是 开销,并且安全地处理大型缓冲区。为此,我有一个256字节的缓冲区,作为成员放在我的课程中,我使用snprinf,传递该缓冲区及其大小。如果snprintf成功,我可以立即重新格式化字符串。如果失败,我分配缓冲区并再次调用snprinf。该缓冲区在类的析构函数中被释放。

3

The fmt library提供fmt::sprintf功能执行printf的兼容格式(包括根据POSIX specification位置参数),并返回其结果作为std::string

std::string s = fmt::sprintf("%s%d", foo, bar); 

声明:我此库的作者。

相关问题