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

发布于 2024-07-10 20:58:22 字数 267 浏览 4 评论 0原文

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

比如:

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

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

output.endRedirect();

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

Does anyone know a good safe way to redirect the output of a printf-style function to a string? The obvious ways result in buffer overflows.

Something like:

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

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

output.endRedirect();

I think the problem is the same as asking, "how many characters will print produce?"
Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

空心↖ 2024-07-17 20:58:23

您可以使用:

std::format:基于fmt::format,这是最安全的标准API

snprintf 如果您正在使用char* - 这可以帮助避免缓冲区溢出,但类型不安全

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

boost::format< /a> 如果您想要一个类似于 printf 且可以处理流的函数。 (根据评论中的贾尔夫)

You can use:

std::format: based on fmt::format, this is the safest standard API

snprintf if you are working with a char* - this can help avoid buffer overflow but not type safe

std::stringstream if you want to use strings (not same as printf but will allow you to easily manipulate the string using the normal stream functions).

boost::format if you want a function similar to printf that will work with streams. (as per jalf in comments)

柒夜笙歌凉 2024-07-17 20:58:23

{fmt} 库 提供了安全的 printf 实现。 例如,fmt::sprintf 格式化并返回 std::string

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

如果您可以使用稍微不同的格式字符串语法,您也可以使用 C++20 < a href="https://en.cppreference.com/w/cpp/utility/format/format" rel="nofollow noreferrer">std::format:

std::string s = std::format("{}{}", foo, bar);

免责声明:我是 {fmt} 和 C++20 std::format 的作者。

The {fmt} library provides a safe printf implementation. For example, fmt::sprintf formats and returns a std::string:

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

If you are OK with a slightly different format string syntax you could also use C++20 std::format:

std::string s = std::format("{}{}", foo, bar);

Disclaimer: I'm the author of {fmt} and C++20 std::format.

还如梦归 2024-07-17 20:58:23

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

可能就是您正在寻找的...

The snprintf() function prints to a string, but only as much as the length given to it.

Might be what you're looking for...

暗地喜欢 2024-07-17 20:58:23

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

如果您愿意,也可以使用 Boost Format 库printf 风格的格式字符串,但想要更安全的东西。

Since you've tagged this as C++ (rather than just C), I'll point out that the typical way to do this sort of thing in C++ is to use stringstream, not the printf family. No need to worry about buffer overflows with stringstreams.

The Boost Format library is also available if you like printf-style format strings but want something safer.

假装爱人 2024-07-17 20:58:23

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

snprintf() returns the number of bytes needed to write the whole string.
So, as a tiny example:

#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;
}

output:

The buffer needs to be 22 bytes.
Filled buffer with 22 bytes.
The buffer contains:
'string 1 and string 2.'
稚然 2024-07-17 20:58:23

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

This StackOverflow question has a similar discussion. Also in that question I present my favorite solution, a "format" function that takes identical arguments to printf and returns a std::string.

有深☉意 2024-07-17 20:58:23

老派:

snprintf()

允许您对写入的数量进行限制,并返回实际写入的大小,并

asprintf()

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

Old school:

snprintf()

allows you to put a limit on the number written, and return the actual written size, and

asprintf()

allocate (with malloc()) a sufficient buffer which then becomes your problem to free(). `asprintf is a GNU libc function now reimplemented in the BSD libc.

三月梨花 2024-07-17 20:58:23

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

维基百科有更多信息。

With C99 you have the snprintf-function which takes the size of the buffer as a parameter. The GNU C-library has asprintf which allocates a buffer for you. For c++ though, you might be better of using iostream.

Wikipedia has more info.

水染的天色ゝ 2024-07-17 20:58:23

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

我发现我需要处理常见情况(例如,缓冲区限制为 256 个字符),无需处理
开销,但仍安全地处理大缓冲区。 为此,我在班级中作为成员分配了一个 256 个字符的缓冲区,并使用 snprinf 传递该缓冲区及其大小。 如果 snprintf 成功,我可以立即返回格式化的字符串。 如果失败,我分配缓冲区并再次调用 snprinf。 缓冲区在类的析构函数中被释放。

I find the printf formatting to be very helpful and easier to use than streams. On the other hand, I do like std::string a lot too. The solution is to use sprintf, but that cannot handle arbitrary buffer size.

I've found that I need to handle common case (say, buffer limited to 256 chars) w/o
overhead, and yet handle the large buffer safely. To do that, I have a buffer of 256 chars alocated in my class as a member, and I use snprinf, passing that buffer and its size. If snprintf succeeds, I can immediately retunr the formatted string. If it fails, I allocate the buffer and call snprinf again. The buffer is deallocated in the class' destructor.

﹂绝世的画 2024-07-17 20:58:23

在 Windows 上:

StringCchPrintf
StringCbPrintf

来自 strsafe.h/lib

On Windows:

StringCchPrintf
StringCbPrintf

from strsafe.h/lib.

江南烟雨〆相思醉 2024-07-17 20:58:23

Microsoft 引入了“安全”crt 函数这。

您可以使用 printf_s()

Microsoft introduce the 'safe' crt functions for this.

You could use printf_s()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文