有没有办法确定sprintf将写多少个字符? 我在C++中工作。< /P>

有没有办法确定sprintf将写多少个字符? 我在C++中工作。< /P>,c++,string,printf,C++,String,Printf,我想使用sprintf编写一个可能非常长的格式化字符串(特别是像_snprintf_s这样的安全计数版本,但想法是一样的)。大约的长度在编译时是未知的,所以我必须使用一些动态分配的内存,而不是依赖一个大的静态缓冲区。有没有办法确定一个特定的sprintf调用需要多少个字符,这样我就可以确保我有足够大的缓冲区 我的退路是,我只需要将格式字符串的长度加倍,然后再试一次。如果可以,很好,如果不行,我将把缓冲区的大小增加一倍,然后再试一次。重复,直到它适合。这并不是最聪明的解决方案 看起来C99支持将N

我想使用sprintf编写一个可能非常长的格式化字符串(特别是像_snprintf_s这样的安全计数版本,但想法是一样的)。大约的长度在编译时是未知的,所以我必须使用一些动态分配的内存,而不是依赖一个大的静态缓冲区。有没有办法确定一个特定的sprintf调用需要多少个字符,这样我就可以确保我有足够大的缓冲区

我的退路是,我只需要将格式字符串的长度加倍,然后再试一次。如果可以,很好,如果不行,我将把缓冲区的大小增加一倍,然后再试一次。重复,直到它适合。这并不是最聪明的解决方案

看起来C99支持将NULL传递给snprintf以获取长度。我想我可以创建一个模块来包装这个功能,如果没有其他东西的话,但我并不热衷于这个想法

也许将fprintf改为“/dev/null”/“nul”可以工作?还有其他想法吗


编辑:或者,有没有办法“分块”sprintf,使它在写的过程中开始?如果可能的话,它可以填充缓冲区,处理它,然后从它所中断的地方开始填充。

< p>我已经寻找了你所说的相同功能,但据我所知,C99方法中的一些东西在C++中是不可用的,因为C++目前没有合并C99中添加的特征(例如SNPRETNF)。
最好的选择可能是使用stringstream对象。这比一个写得很清楚的sprintf调用要麻烦一些,但它会起作用。

我会使用两阶段的方法。通常,大部分输出字符串将低于某个阈值,只有少数字符串会更大

第1阶段,使用大小合理的静态缓冲区,如4K。由于
snprintf()
可以限制写入的字符数,因此不会出现缓冲区溢出。从
snprintf()
返回的是如果缓冲区足够大,它将写入的字符数

如果对
snprintf()
的调用返回的值小于4K,则使用缓冲区并退出。如前所述,绝大多数电话都应该这样做

有些人不会,那就是你进入第二阶段的时候。如果对
snprintf()
的调用不适合4K缓冲区,那么至少现在您知道需要多大的缓冲区了

使用
malloc()
,分配一个足以容纳它的缓冲区,然后
snprintf()。当缓冲区用完后,释放它

snprintf()
之前的几天里,我们在一个系统上工作,我们通过将一个文件句柄连接到
/dev/null
并使用
fprintf()
获得了相同的结果/dev/null总是保证获取尽可能多的数据,因此我们实际上可以从中获得大小,然后在必要时分配一个缓冲区

请注意,并非所有系统都有
snprintf()
(例如,我知道它是Microsoft C中的
\u snprintf()
),因此您可能需要找到执行相同任务的函数,或者返回到
fprintf/dev/null
解决方案

如果可以在大小检查
snprintf()
和缓冲区的实际
snprintf()
之间更改数据,也要小心(即线程的输出)。如果大小增加,将导致缓冲区溢出损坏

如果您遵循这样一条规则,即数据一旦交给某个函数,在交回之前就只属于该函数,那么这不会是一个问题。

请看一看。它使用您建议的扩大缓冲区大小的解决方案


// -------------------------------------------------------------------------
//功能:FormatV
//void FormatV(PCSTR szFormat、va_list、argList);
//
//说明: //此函数使用sprintf样式的格式规范格式化字符串。 //它大致猜测所需的缓冲区大小,然后进行尝试 //依次增大缓冲区,直到找到足够大的缓冲区或 //超过阈值(最大尝试次数)。 // //参数: //szFormat—保存输出格式的PCSTR //argList-用于变量参数列表的Microsoft特定va_列表 // //返回值: //-------------------------------------------------------------------------

Return value Upon successful return, these functions return the number of characters printed (not including the trailing '\0' used to end output to strings). The functions snprintf and vsnprintf do not write more than size bytes (including the trailing '\0'). If the output was truncated due to this limit then the return value is the number of characters (not including the trailing '\0') which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated. (See also below under NOTES.) If an output error is encountered, a negative value is returned. void FormatV(const CT*szFormat,va_list argList) { #ifdef SS_ANSI int nLen=sslen(szFormat)+标准尺寸; ssvsprintf(GetBuffer(nLen)、nLen-1、szFormat、argList); 释放缓冲区(); #否则 CT*pBuf=NULL; int-nChars=1; int-nUsed=0; 尺寸\类型实际=0; intntry=0; 做 { //超过线性增长(例如512、1536、3072等) nChars+=((nTry+1)*FMT\U块大小); pBuf=重新解释铸件(_alloca(尺寸(CT)*nChars)); nUsed=ssnprintf(pBuf、nChars-1、szFormat、argList); //确保正确的零终止。 nActual=nUsed==-1?nChars-1:SSMIN(nUsed,nChars-1); pBuf[nActual+1]='\0'; }而(使用<0&&nTry++分配(pBuf、nActual); #恩迪夫 }

snprintf的手册页上写着:

int how_much_space = snprintf(NULL, 0, fmt_string, param0, param1, ...);

正如其他人提到的,
snprintf()
将返回缓冲区中所需的字符数,以防止输出被截断。您可以简单地使用0 buffer length参数调用它,以获得所需的大小,然后使用适当大小的缓冲区

为了稍微提高效率,您可以使用足够大的缓冲区来调用它,如果输出被截断,则只需再次调用
snprintf()
。为了确保b
int how_much_space = snprintf(NULL, 0, fmt_string, param0, param1, ...);
std::ostringstream oss;
oss << a << " " << b << std::endl;
#define _GNU_SOURCE
#include <stdio.h>

int main(int argc, char const *argv[])
{
    char *hi = "hello"; // these could be really long
    char *everyone = "world";
    char *message;
    asprintf(&message, "%s %s", hi, everyone);
    puts(message);
    free(message);
    return 0;
}