1

介绍

我继承了一个用 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 界面中做错了什么,因为它认为必须将整数视为双精度数?我怎么能确定这不会在谁知道何时何地发生?解决此问题的最佳方法是什么?

4

1 回答 1

2

Excel 内部不保存整数 - 所有数字(整数、日期、时间、货币等)都保存为双精度数。所以 Oper val.num 始终是双精度数,而 xltypeNum 的操作数始终是双精度数。
(操作员可以在 val.w 中保存整数,但只能作为 XLM 宏流控制之类的东西的一部分,这些东西已经过时了几十年,在实践中不太可能得到满足)。
我不知道为什么您在 Excel 2007 中得到 9.9999999 - 您如何将值传递给 Oper?

于 2012-12-07T16:02:41.627 回答