Introduction
I have inherited a legacy plugin project (in C++) developed with VS2008, xlw 2.0 and excel 2003.
I have managed to port it to xlw 4.0 headers (some method changed name when support for Excel 2007 was added, things like that). I am not generating anything (yet), since the old code was written by hand and I am not going to change something which is working, and has a reasonable structure and code logic only for the sake of it.
The code works as expected under excel 2003. I tried today with excel 2010 and found a most puzzling (and scarying) bug.
Puzzling behaviour
I receive (from a VBA macro) a column (n rows, 1 column) of numbers (small positive integers by construction) as a XlfOper & and I want to convert it to an (old-style) array. The code is basically going through each row and then is calling the AsInt() method on the XlfOper corresponding to the given row. Something like:
for (long iy = 0; iy < numcols; ++iy)
{
for (long ix = 0; ix < numrows; ++ix)
convertXflOper( x(ix, iy), a1D[iy*numrows + ix] );
}
where a1D is the 1 dimensional array type used in this particular project, and convertXflOper is a template function, which is for these types:
void convertXflOper (const XlfOper &x, long & y)
{
y = x.AsInt();
}
At a given row, I have in the excel workbook the number 10.
Under Excel 2003, this is converted to 10. Under Excel 2010 this is converted to 9.
I have debugged it, and the problem is that it is really reading not 10, but a double approximation to it. The output (of the immediate window) is
x.lpxloper4_->val.num
9.9999999999999982 // wrong: I am not asking for 10.0, I am asking for 10
in Excel 2010, and
x.lpxloper4_->val.num
10.000000000000000 // right: an integer is an integer
in Excel 2003. So the C++ code, as pretty (or not) as it is, appears not to be at fault. The AsInt() method behaves like a cast, and static_cast<long>(9.9999999999999982) is 9, not 10.
Question
This thing was going to bite me quite badly, mainly because it was very easy to overlook it: for many other integers values it works correctly both in excel 2003 and 2010.
What am I doing wrong in the excel interface in that it thinks that an integer must be treated as a double? How can I be sure that this is not going to happen who-knows-where-and-when? What is the best way to fix this?
Excel does not hold integers internally - all numbers (integers, dates, times, currency etc) are held as doubles. So the Oper val.num is always a double, and an oper of xltypeNum is always a double.
(Opers can hold integers in val.w but only as part of things like XLM Macro flow control which have been obsolete for decades and are unlikely to be met in practice).
I don't know why you get 9.9999999 in Excel 2007 - how are you passing the value to the Oper?
来源:https://stackoverflow.com/questions/13762316/representation-of-integers-in-excel-2010-vs-excel-2003-c-plugin