今天用C++ Builder 2010寫一段小代碼,用到了集合類,可集合運算結果怎麼也不對,排除了其它原因,最後確定應該是集合類源代碼的問題,下面是一段集合類的測試代碼:
enum TTest{tt0, tt15 = 15, tt16 = 16};
typedef Set<TTest, tt0, tt16> TTests;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TTests t1 = TTests() << tt15;
TTests t2 = TTests() << tt16;
ShowMessage(t1.ToInt()); // 32768
ShowMessage(t2.ToInt()); // 16777216
}
測試代碼中的集合類變量t1,t2分別定義為第15位和第16位,顯示結果應該分別為32768和65536,t1結果32768是正確的,t2顯示卻為16777216,顯然是錯誤的。
接下來,我用Delphi 2010寫了類似的測試代碼:
type
TTest = (tt0, tt15 = 15, tt16 = 16);
TTests = set of TTest;
procedure TForm1.Button1Click(Sender: TObject);
var
t1, t2: TTests;
begin
t1 := [tt15];
t2 := [tt16];
ShowMessage(IntToStr(LongWord(t1))); // 32768
ShowMessage(IntToStr(LongWord(t2))); // 65536
end;
而Delphi 2010代碼顯示結果完全正確。
很明顯,C++Builder 2010代碼中的集合類變量t2向左多移了8位,即16777216是第24位置位後的結果。
我調出C++Builder 2010集合類源代碼文件sysset.h,查看了一下其ToInt函數,發現問題就出在這裡,請看源碼中數據定義和ToInt函數代碼:
template<class T, unsigned char minEl, unsigned char maxEl>
class RTL_DELPHIRETURN SetBase
{
protected:
unsigned char Data[((((int)(maxEl/8))-((int)(minEl/8))+1) != 3)?
(((int)(maxEl/8))-((int)(minEl/8))+1): 4];
};
template<class T, unsigned char minEl, unsigned char maxEl>
class RTL_DELPHIRETURN Set : SetBase<T, minEl, maxEl>
{
......
int __fastcall ToInt(void) const
{
#pragma option push -w-inl
int Result = 0;
for (int i = sizeof(Data)-1; i >= 0; i--)
{
Result |= Data[i];
Result <<= (i * sizeof(unsigned char) * 8);
}
return Result;
#pragma option pop
}
......
};