安全printf到字符串的最佳方法?

时间:2009-01-12 18:06:13

标签: c++ stl

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

类似的东西:

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

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

output.endRedirect();

我认为问题与询问一样,“会打印出多少个字符?” 想法?

11 个答案:

答案 0 :(得分:27)

您可以使用:

std::snprintf如果你正在使用char *

std::stringstream如果你想使用字符串(与printf不同,但允许你使用普通的流函数轻松操作字符串)。

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

fmt::format正在标准化,可能会成为std::format

答案 1 :(得分:10)

snprintf()函数打印到一个字符串,但只有给它的长度。

你可能正在寻找......

答案 2 :(得分:6)

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

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

免责声明:我是这个图书馆的作者。

答案 3 :(得分:5)

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

如果您喜欢printf样式的格式字符串但想要更安全的东西,Boost Format库也可用。

答案 4 :(得分:4)

旧学校:

snprintf()

允许您对写入的数字设置限制,并返回实际的写入大小,

asprintf()

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

答案 5 :(得分:4)

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

答案 6 :(得分:4)

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

答案 7 :(得分:1)

使用C99,您可以使用snprintf函数,该函数将缓冲区的大小作为参数。 GNU C库有asprintf为您分配缓冲区。但是对于c ++,你最好使用iostream。

Wikipedia有更多信息。

答案 8 :(得分:1)

我发现printf格式化非常有用,比流更容易使用。另一方面,我也喜欢std :: string。解决方案是使用sprintf,但无法处理任意缓冲区大小。

我发现我需要处理普通情况(例如,缓冲区限制为256个字符)w / o 开销,但安全地处理大缓冲区。为此,我在我的类中有一个256个字符的缓冲区作为成员,我使用snprinf,传递缓冲区及其大小。如果snprintf成功,我可以立即重新编译格式化的字符串。如果失败,我分配缓冲区并再次调用snprinf。缓冲区在类'析构函数中释放。

答案 9 :(得分:0)

在Windows上:

StringCchPrintf
StringCbPrintf

来自strsafe.h/lib

答案 10 :(得分:-1)

Microsoft为此引入了“safe”crt函数。

您可以使用printf_s()