介绍
我继承了一个用 VS2008、xlw 2.0 和 excel 2003 开发的遗留插件项目(C++)。
我已经设法将它移植到 xlw 4.0 标头(添加对 Excel 2007 的支持时,某些方法更改了名称,诸如此类)。我没有生成任何东西(还),因为旧代码是手工编写的,我不会更改正在工作的东西,并且只是为了它而具有合理的结构和代码逻辑。
该代码在 excel 2003 下按预期工作。我今天尝试使用 excel 2010 并发现了一个最令人费解(和可怕)的错误。
令人费解的行为
我(从 VBA 宏)接收一列(n 行,1 列)数字(通过构造的小正整数)作为 XlfOper & 我想将其转换为(旧式)数组。代码基本上遍历每一行,然后在与给定行对应的 XlfOper 上调用 AsInt() 方法。就像是:
for (long iy = 0; iy < numcols; ++iy)
{
for (long ix = 0; ix < numrows; ++ix)
convertXflOper( x(ix, iy), a1D[iy*numrows + ix] );
}
其中 a1D 是此特定项目中使用的一维数组类型,convertXflOper 是模板函数,适用于以下类型:
void convertXflOper (const XlfOper &x, long & y)
{
y = x.AsInt();
}
在给定的行中,我在 excel 工作簿中有数字 10。
在 Excel 2003 下,这将转换为 10。在 Excel 2010 下,这将转换为 9。
我已经对其进行了调试,问题是它实际上读取的不是 10,而是它的双重近似值。(即时窗口的)输出是
x.lpxloper4_->val.num
9.9999999999999982 // wrong: I am not asking for 10.0, I am asking for 10
在 Excel 2010 中,以及
x.lpxloper4_->val.num
10.000000000000000 // right: an integer is an integer
在 Excel 2003 中。所以 C++ 代码,不管它漂亮(或不漂亮),似乎都没有错。AsInt() 方法的行为类似于强制转换,并且static_cast<long>(9.9999999999999982)
是 9,而不是 10。
问题
这件事让我很伤心,主要是因为它很容易被忽视:对于许多其他整数值,它在 excel 2003 和 2010 中都能正常工作。
我在 excel 界面中做错了什么,因为它认为必须将整数视为双精度数?我怎么能确定这不会在谁知道何时何地发生?解决此问题的最佳方法是什么?