C++ Builder 2010集合類的一個BUG

來源:互聯網
上載者:User

今天用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    }          ......        };

更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/cplus/

上面測試用的集合類TTests最小成員值=0,最大成員值=16,按源碼資料長度定義公式計算得3,Byte類型的數組Data長度=4,測試代碼中的集合類變數t1和t2的資料分別為"\0\x80\0\0"和"\0\0\1\0",在ToInt函數轉換時,t1的有效起始下標i=1,Result賦值0x80後共左移了2次8位,結果為0x8000(32768);而t2的有效起始下標i=2,Result賦值1後左移了3次共24位(即2 * 1 * 8 = 16,1 * 1 * 8 = 8,0 * 1 * 8 = 0),結果為0x1000000(16777216)。

可以將源碼中ToInt函數做如下修改:

  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];      if (i)          Result <<= (sizeof(unsigned char) * 8);    }    return Result;  #pragma option pop    }

我只查看了C++Builder 2010,而且也只涉及ToInt函數,其它版本或函數有無問題不清楚,顯然這個BUG在程式中有可能是致命的,望各位C++Builder程式員警惕。

作者:csdn部落格 阿發伯

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.