安全地将 printf 打印到字符串的最佳方法? [复制]
Posted
技术标签:
【中文标题】安全地将 printf 打印到字符串的最佳方法? [复制]【英文标题】:Best way to safely printf to a string? [duplicate] 【发布时间】:2009-01-12 18:06:13 【问题描述】:有没有人知道将 printf 样式函数的输出重定向到字符串的安全的好方法?显而易见的方式会导致缓冲区溢出。
类似:
string s;
output.beginRedirect( s ); // redirect output to s
... output.print( "%s%d", foo, bar );
output.endRedirect();
我认为这个问题与问“打印会产生多少个字符?”是一样的。 想法?
【问题讨论】:
将之前提出的问题标记为重复是没有意义的。投票重新开放(我们应该关闭另一个重复)。 就size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */ char *str = malloc(nbytes); snprintf(str, nbytes, "%s", name);
【参考方案1】:
你可以使用:
std::snprintf
如果您使用的是 char*
std::stringstream
如果您想使用字符串(与 printf 不同,但可以让您使用普通流函数轻松操作字符串)。
boost::format
如果你想要一个类似于 printf 的函数来处理流。 (根据 cmets 中的 jalf)
fmt::format
自c++20以来就已经标准化了std::format
【讨论】:
和 boost::format 使用 C++ 流获得类似 printf 的格式化功能 如果你正在使用wchar_t*
,你也可以使用std::snprintf
,只要你使用mbstowcs_s
分配转换后的缓冲区。【参考方案2】:
snprintf()
函数打印到一个字符串,但只打印给它的长度。
可能就是你要找的……
【讨论】:
比我快。这是老派的做法。 您可以使用不需要长度的 sprintf。正如他所要求的,这也不适用于字符串...... @abyx - 准点!最好为 std::string 添加一个示例,例如snprintf(target, SIZE, "%s%d", foo.c_str(), bar); @Adam - sprintf 是不安全的,这正是发帖者要求如何避免的问题【参考方案3】:The fmt library 提供 fmt::sprintf
函数,该函数执行 printf 兼容格式(包括根据 POSIX specification 的位置参数)并将结果作为 std::string
返回:
std::string s = fmt::sprintf( "%s%d", foo, bar );
免责声明:我是这个库的作者。
【讨论】:
【参考方案4】:由于您已将其标记为 C++(而不仅仅是 C),我将指出在 C++ 中执行此类操作的典型方法是使用 stringstream,而不是 printf 系列。无需担心字符串流导致缓冲区溢出。
如果您喜欢 printf 样式的格式字符串但想要更安全的东西,也可以使用 Boost Format 库。
【讨论】:
Boost 格式+1(击败我 :)【参考方案5】: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】:This *** question 也有类似的讨论。同样在那个问题中,我提出了我最喜欢的解决方案,一个“格式”函数,它接受与 printf 相同的参数并返回一个 std::string。
【讨论】:
【参考方案7】:老派:
snprintf()
允许您限制写入的数量,并返回实际写入的大小,并且
asprintf()
分配(与malloc()
)一个足够的缓冲区,然后成为free()
的问题。 `asprintf 是一个 GNU libc 函数,现在在 BSD libc 中重新实现。
【讨论】:
【参考方案8】:在 C99 中,您有 snprintf 函数,它将缓冲区的大小作为参数。 GNU C 库有 asprintf 为你分配一个缓冲区。不过,对于 c++,您可能会更好地使用 iostream。
Wikipedia 有更多信息。
【讨论】:
【参考方案9】:我发现 printf 格式比流格式更有用且更易于使用。另一方面,我也很喜欢 std::string 。解决方案是使用 sprintf,但它无法处理任意缓冲区大小。
我发现我需要处理常见情况(例如,缓冲区限制为 256 个字符)w/o 开销,但安全地处理大缓冲区。为此,我有一个 256 个字符的缓冲区作为成员分配在我的班级中,我使用 snprinf,传递该缓冲区及其大小。如果 snprintf 成功,我可以立即返回格式化字符串。如果失败,我分配缓冲区并再次调用 snprinf。缓冲区在类的析构函数中被释放。
【讨论】:
【参考方案10】:在 Windows 上:
StringCchPrintf
StringCbPrintf
来自strsafe.h/lib
。
【讨论】:
【参考方案11】:微软为此引入了 'safe' crt 函数。
你可以使用printf_s()
【讨论】:
不适用于任何其他符合标准的实现,太糟糕了。 另外,唯一的区别是,如果“安全”crt 检测到某些未定义的行为,它们会自行崩溃。这并没有绕过他遇到的问题。以上是关于安全地将 printf 打印到字符串的最佳方法? [复制]的主要内容,如果未能解决你的问题,请参考以下文章