c语言buf max_size,关于c ++:sprintf(buf,“%.20g”,x)// buf应该多大?

我正在将双精度值转换为这样的字符串:

std::string conv(double x) {

char buf[30];

sprintf(buf,"%.20g", x);

return buf;

}

我已经将缓冲区的大小硬编码为30,但是不确定是否足够大。

如何找到所需的最大缓冲区大小?

从32位切换到64位时,精度是否会更高(因此需要增加缓冲区)?

PS:出于性能原因,我不能使用ostringstream或boost::lexical_cast(请参阅此)

I have hardcoded the buffer size to 30, but am not sure if this is large enough for all cases.

它是。 %.20g在尾数中指定20位数字。小数点后加1。 1(可能的符号),5(" e + 308"或" e-308"),指数越差越好。和1表示终止为null。

20 + 1 + 1 + 5 + 1 = 28。

Does the precision get higher (and therefore buffer needs to increase) when switching from 32bit to 64?

没有。

在两种体系结构中,double大小相同。如果将变量声明为long double,则指数" e + 4092"中可能再有1位数字,但仍可容纳30个字符。但仅在X86上,并且仅在较旧的处理器上。

long double是一个过时的80位浮点值形式,它是486 FPU的本机格式。该FPU架构无法很好地扩展,因此由于支持SSE样式指令而被丢弃,因为SSE样式指令的最大可能浮点值为64位双精度。

只要您将打印输出中的尾数限制为20位,那么长30个字符的缓冲区就足够了。

我似乎记得,如果使用NULL目标调用sprintf,它不会执行任何操作。但是,它会返回它"写"的字符数。如果我是对的(并且似乎找不到该源),则可以执行以下操作:

// find the length of the string

int len = sprintf(NULL, fmt, var1, var2,...);

// allocate the necessary memory.

char *output = malloc(sizeof(char) * (len + 1)); // yes I know that sizeof(char) is defined as 1 but this seems nicer.

// now sprintf it after checking for errors

sprintf(output, fmt, var1, var2,...);

另一个选择是使用snprintf,它允许您限制输出的长度:

#define MAX 20 /* or whatever length you want */

char output[MAX];

snprintf(output, MAX, fmt, var1, var2,...);

snprintf将缓冲区的大小作为参数,并且不允许输出字符串超过该大小。

-1:OP正在寻找性能,解决方案1运行两次printf()并调用malloc(),这有很大的开销:那非常糟糕。解决方案2使用snprintf(),它比printf()慢。使用带有足够大缓冲区的printf()是性能的最佳解决方案,这是OP要求的(不管是不是很傻)!

+1,用于snprintf,即使它不是标准(尚未)。 snprintf和sprintf之间的性能差异可以忽略不计,尤其是格式化加倍时。

@安德烈亚斯,你说的对。我错过了性能要求。但是请注意,他没有使用printf,而是使用了sprintf。

printf("%.20g", 1.79769e+308);是1.7976900000000000632e+308,包括尾随 0在内的27个字节。为了确定我会选择64或128。

(因为它在堆栈上并在您还可以使用大缓冲区(甚至2048字节)后立即发布,而不会遇到非嵌入式应用程序的问题)

另外,您确定程序的瓶颈是lexical_cast ..?做你对我来说似乎很愚蠢的事

我们在多线程应用程序中编写具有双值的大型CSV文件,并且由于某些原因使用lexical_cast时,在某些计算机上它变得非常慢。当使用sprintf时,速度要快20倍。

好吧,如果它是普通的桌面应用程序,它将有大量的堆栈,因此,使用buf [2048]不必担心!

32字节就可以了-您显示它不需要那么大,但是即使使用5位数的指数,32也有一些备用空间。

我不喜欢看到这样的2k缓冲区。在这种情况下,它足够大,但是让我想到:"如果程序员不相信1k足够,或者1.5k,那么(a)他为什么相信2k是?,以及(b)他还做什么?不自信吗?"

安全胜过遗憾?没有信心可以跳2码没有错,但是绝对可以确保可以跳半码。第二个很明显,第一个不明显。 2k(甚至是1k,我说2k只是因为在这种情况下堆栈空间是"可用的",所以数量实际上并不重要)就足够了,而32k则不够。那么读取代码的程序员呢?如果我看到32我会担心它溢出,如果我说1k / 2k / 10k,我不会

可以,但是我实际上已经修复了代码中的缓冲区溢出错误,有人说" X显然足够大",没有费心证明它确实足够大,没有费心在运行时进行测量,并且在某些情况下被证明是错误的。如果可以证明"%.20g"格式适合2k,那么可以证明它适合64个字节。如果您无法证明这一点,那么您就不要说"比对不起更好",而您说"比实际要好得多"。由于可以证明这一点,所以我只说一小部分,并附上一条评论,向未来的读者表明您已经考虑过这一点。

也就是说,Ive还修复了某些人(可能是我)计算出最大长度并忘记了某些内容的错误,就像Alok用减号所做的那样。结果是溢出或截断,这会在以后导致问题,具体取决于是strcpy还是strncpy。出于这个原因,我认为"计算限制并加几个"是一个不错的主意-您不必相信自己正确无误即可。但是IMO如果我不能相信自己在最近的1024字节之内是正确的,我有麻烦了;-)

如果您在支持POSIX或C99的平台上,则应该能够使用snprintf来计算所需缓冲区的大小。 snprintf带有一个参数,该参数指示您要传入的缓冲区的大小;如果字符串的大小超过该缓冲区的大小,它将截断输出以适合缓冲区,并返回适合整个输出所需的空间量。您可以使用此输出来分配大小正确的缓冲区。如果只想计算所需缓冲区的大小,则可以传入NULL作为缓冲区,而大小为0以计算所需的空间。

int size = snprintf(NULL, 0,"%.20g", x);

char *buf = malloc(size + 1); // Need the + 1 for a terminating null character

snprintf(buf, size + 1,"%.20g", x);

记住使用free(buf)以避免内存泄漏。

问题是它不能在Visual Studio中运行,而Visual Studio仍然不支持C99。虽然它们具有类似snprintf的内容,但是如果传入的缓冲区太小,它不会返回所需的大小,而是返回-1,这是完全没有用的(并且它不接受NULL作为缓冲区,即使长度为0)。

如果您不介意截断,则可以将snprintf与固定大小的缓冲区一起使用,并确保不会溢出:

char buf[30];

snprintf(buf, sizeof(buf),"%.20g", x);

确保您在snprintf上检查平台文档;特别是,如果平台被截断,某些平台可能不会在字符串末尾添加终止空值,因此您可能需要自己执行。

这是一个程序,用于打印double可以用于任何系统的最大值和最小值所需的位数:

#include

#include

int main(void)

{

double m = DBL_MAX;

double n = DBL_MIN;

int i;

i = printf("%.20g

", m);

printf("%d

", i);

i = printf("%.20g

", n);

printf("%d

", i);

return 0;

}

对我来说,它打印:

1.7976931348623157081e+308

27

2.2250738585072013831e-308

27

由于27包含换行符,但不包含字符串的终止0,我想说在这个系统上,27应该足够了。对于long double,答案在我的系统上分别是LDBL_MAX和LDBL_MIN的27和28。

手册页(在我的sprintf上是关于%g的):

The double argument is converted in

style f or e (or F or E for G

conversions). The precision specifies the number of

significant

digits. If the precision is missing, 6 digits are given; if the

precision is zero, it is treated as 1. Style e is used if the

exponent from its conversion is less than -4 or greater

than or

equal to the precision. Trailing zeros are removed from the

fractional part of the result; a decimal point appears only

if it

is followed by at least one digit.

C语言中的措辞与此类似。

因此,如果您使用上述程序的输出作为数组大小,您会很安全。

我也在回答中使用了DBL_MAX,但是由于采用指数表示法,它可能不是最长的(或者可能是最长的,我不知道)。

请记住,您需要为负数增加一个字符:-)

真好我应该考虑一下。

@Andreas:由于精度指定为20,所以任何大于等于1e20的值都将用指数符号打印。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值