【问题标题】:Using sprintf without a manually allocated buffer在没有手动分配缓冲区的情况下使用 sprintf
【发布时间】:2010-09-22 15:22:54
【问题描述】:

在我正在处理的应用程序中,日志记录工具使用sprintf 来格式化写入文件的文本。所以,像:

char buffer[512];
sprintf(buffer, ... );

当发送的消息对于手动分配的缓冲区来说太大时,这有时会导致问题。

有没有办法获得sprintf 行为而不必像这样手动分配内存?

编辑:虽然sprintf 是 C 操作,但我正在寻找 C++ 类型的解决方案(如果有的话!)让我获得这种行为......

【问题讨论】:

    标签: c++ c string memory


    【解决方案1】:

    “日志工具使用 sprintf 格式化写入文件的文本”

    fprintf() 不施加任何大小限制。如果您可以将文本直接写入文件,请这样做!

    不过,我假设有一些中间处理步骤。如果您知道自己需要多少空间,您可以使用malloc() 分配那么多空间。

    有时像这样的一种技术是分配一个合理大小的缓冲区(在 99% 的情况下足够大),如果不够大,则将数据分解为您一个一个处理的块。

    【讨论】:

    • 文件访问比内存访问慢得多。这就是为什么中间 sprintf 不是一个坏主意的原因之一。
    • 您可以通过缓冲文件(如果可用)获得大部分好处。仍然有调用开销,但至少你没有碰到磁盘。
    【解决方案2】:

    使用 sprintf 的 vanilla 版本,无法防止数据覆盖传入的缓冲区。无论内存是手动分配的还是在堆栈上分配的,都是如此。

    为了防止缓冲区被覆盖,您需要使用更安全的 sprintf 版本之一,例如 sprintf_s(仅限 Windows)

    http://msdn.microsoft.com/en-us/library/ybk95axf.aspx

    【讨论】:

    • 可以使用 vanilla sprintf() 防止缓冲区溢出,例如sprintf(buf, "%.*s", buf_size - 1, input_string);但这仅适用于已知的固定格式字符串。
    【解决方案3】:

    不,您不能使用sprintf() 分配足够的内存。替代方案包括:

    • 使用snprintf() 截断消息 - 不能完全解决您的问题,但可以防止缓冲区溢出问题
    • 双倍(或三倍或...)缓冲区 - 除非您处于受限环境中
    • 使用 C++ std::stringostringstream - 但是你会失去 printf 格式,你必须使用
    • 使用 Boost Format 附带类似 printf 的 % 运算符

    【讨论】:

    • 请注意,snprintf() 告诉您需要多少空间,因此您可以根据需要使用两次,第一次使用静态缓冲区,第二次使用动态分配的缓冲区.
    • -1 表示第二个建议(将缓冲区大小加倍。由于您不知道最大字符串长度,因此即使乘以十亿也不能保证它不会溢出。)
    【解决方案4】:

    您可以使用 asprintf(3)(注意:非标准)为您分配缓冲区,因此您无需预先分配它。

    【讨论】:

    • 请提及此功能在不同系统中的可用性,因为它既不是标准的 C lib 也不是 POSIX。
    • 主要是Linux——也可能是BSD。还有一个 vasprintf()。
    • 哦,是的,对此感到抱歉...... OP 没有提到哪个平台,所以我只是把它扔在那里。它可以在 Linux、BSD 和 Mac OS X 上找到……它现在是 gnuc 库的标准部分。
    【解决方案5】:

    我也不知道避免分配的版本,但如果 C99 sprintfs 允许将 NULL 指针作为字符串。效率不高,但这会给你完整的字符串(只要有足够的内存可用)而不会冒溢出的风险:

    length = snprintf(NULL, ...);
    str = malloc(length+1);
    snprintf(str, ...);
    

    【讨论】:

    • 如果你使用C99,你也可以只使用一个变长数组,所以不要mallocing str,只需将它声明为“char str[length+1];”在调用 snprintf 之后。不需要释放它,因为它在堆栈上。
    • 如果您使用的是 MSVC 运行时,您会发现 snprintf 返回一个负值而不是所需的长度。因此,如果您想要 MSVC 下所需的长度,则需要使用不同的函数 _vscprintf [msdn.microsoft.com/en-us/library/w05tbk72.aspx]
    猜你喜欢
    • 2011-03-15
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-16
    • 1970-01-01
    • 2011-10-17
    • 2011-03-02
    相关资源
    最近更新 更多