双精度值的最大长度是多少?

3

我从 hp fortify 中收到了缓冲区溢出:格式化字符串警告。请问您能否告诉我一个 double 值的最大长度是多少?在以下示例中,dCode 是一个存储在 pszPref 中的双精度浮点数值。

代码:

TCHAR pszPref[64];
_stprintf(pszPref, "%f", dCode);

我想确认dCode的最大长度,无论是否带小数。


2
为什么会有踩票?浮点数的序列化是棘手的。 - Bathsheba
你可能会对我在相关问题上的这个回答感兴趣。 - Alexey Frunze
1
使用 snprintf 来避免任何缓冲区溢出的可能性。 - M.M
4个回答

0

由于十进制基数通常不是浮点数的最自然表示方式,因此没有最大字符串长度:显示精确浮点数可能需要无限数量的十进制数字。

幸运的是,对于IEEE754浮点双精度,15个有效数字就足够了。如果您使用该精度编写并读回一个浮点双精度,则会得到与开始时相同的数字。(使用"%.15E"作为printf-样式格式化程序。)尽管C++标准不坚持double是那种类型,但它最常见,并且对于MFC是目标的系统,它可能是。

您可以通过检查std::numeric_limits<double>::is_iec559来进行(几乎)确定。


如果我们包括小数值,它可以超过64吗? - Tansheet
是的,不过不用担心。15位有效数字足够了。不过你需要使用科学计数法。请参见此答案中的修改。 - Bathsheba
不,你永远不需要“无限数量的十进制数字”。 - Henrik
是的,你需要。我可以创造出一个浮点表示,符合C++标准,需要无限数量。但实际上,“is_iec559”检查和15个有效数字就足够了。 - Bathsheba

0

由于您没有为格式提供精度参数,printf及其相关函数默认使用6位小数。

iee 754双精度浮点数的最小值为-1.7976931348623157E+308

要以6位小数的精度打印该数字,您需要一个字符用于符号,一个字符用于小数点,308个字符用于整数部分和6个小数位,总共316个字符。不要忘记为空终止符分配额外的字符。因此,一个317个字符的数组应该足够,但只有在使用iee 754时才能保证,这在c++标准中是保证的。

hp fortify可能不知道这一点,而且不能安全地假设iee 754,因此无论您使用多大的数组,都可能无法摆脱警告。为确保不会发生溢出,请使用snprintf或类似函数,允许传递缓冲区大小。


0

无论目标缓冲区实际有多大,只要使用未限定的 CRT 字符串输出方法(sprintfstrcpystrcat 等),Fortify 就会产生警告。近年来,Microsoft 已经为所有这些方法制作了“安全”版本,这些版本具有 _s 扩展名,例如 _stprintf_s

与截断版本(snprintf 等)相比,这些方法改进了在溢出发生时调用 error handler 的方式。截断方法不会溢出缓冲区,但它们理论上可以用于制作一些无效的缓冲区内容,从而导致连锁错误,可能被黑客用作攻击向量。

因此,为了保护您的代码并消除 Fortify 的警告:

  1. 使用回调方法处理溢出错误,调用 _set_invalid_parameter_handlerstdlib.h)。

  2. 使用 _stprintf_s(pszPref, sizeof(pszPref)/sizeof(pszPref[0]), "%f", dCode)


1
_stprintf_s 函数期望缓冲区大小以字符数为单位,而不是字节数。由于 Windows 使用 UTF-16(并且项目通常定义了 UNICODE),因此您创建了您试图解决的缓冲区溢出问题。相反,使用函数模板,可以推断出缓冲区大小:_stprintf_s(pszPref, _T("%f"), dCode); - IInspectable

0
虽然没有直接回答你的问题,但你可以使用 std::to_string 来使用 char 数组。
例如:
std::string strPref = std::to_string(dCode);

注意:如果您使用的是Visual Studio 2010,您需要将dCode转换为在此答案中提到的

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接