zoukankan      html  css  js  c++  java
  • 发现C++Builder 2010一组类BUG

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


        上面測试用的集合类TTests最小成员值=0,最大成员值=16,按源代码数据长度定义公式计算得3。Byte类型的数组Data长度=4,測试代码中的集合类变量t1和t2的数据分别为"x80"和"1",在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程序猿警觉。


  • 相关阅读:
    Python基础
    熟悉常见的Linux操作
    大数据概述
    实验报告(3)-语法分析
    LL(1)文法
    简化版C语言文法
    实验报告(1)-词法分析
    中文词频统计
    综合练习:英文词频统计
    字符串练习
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5027287.html
Copyright © 2011-2022 走看看