delphi - 使用默认排序在 64 位与 32 位中对 TList<TPair<Integer,integer>> 进行排序

标签 delphi generics 64-bit delphi-xe2

在 32 位和 64 位下编译时,TPair 的默认排序似乎存在差异。在 32 位下,默认排序的行为就像按对的键排序,在 64 位下,它看起来按值排序。这是可以预料的,还是我错过了什么?

使用 Delphi XE2,更新 4 进行测试。在 VCL 应用程序中,将按钮、复选框和列表框拖放到屏幕上,声明以下类型

type TPairComparer = TComparer<TPair<integer,integer>>;

然后将下面的代码放入按钮 OnClick 中并运行。在 32 位下,使用默认排序,按键列出对,即 1、2、3、4、5、6。在 64 位下,这些对按值列出,即 2、5、6、7、8、9,而不是按键列出。

为了使代码在两个平台上一致地工作,我需要指定自己的比较器来强制在 64 位可执行文件上按键排序。

 procedure TForm1.Button1Click(Sender: TObject);
 var PriorityList           : TList<TPair<Integer,integer>>;
     Pair                   : TPair<integer,integer>;
     PairComparer           : IComparer<TPair<integer,integer>>;
     iLoop                  : integer;
 begin

 PriorityList := TList<TPair<Integer,integer>>.Create;

 PairComparer := TPairComparer.Construct(
 function(const Left, Right: TPair<integer,integer>): Integer
 begin
      case Left.Key = Right.Key of
           true : Result := 0;
      else        case Left.Key < Right.Key of
                       true : Result := -1;
                  else        Result := +1;
                  end;
      end;
 end);

 Pair.Key   := 6;
 Pair.Value := 6;
 PriorityList.Add(Pair);

 Pair.Key   := 5;
 Pair.Value := 5;
 PriorityList.Add(Pair);

 Pair.Key   := 4;
 Pair.Value := 8;
 PriorityList.Add(Pair);

 Pair.Key   := 3;
 Pair.Value := 9;
 PriorityList.Add(Pair);

 Pair.Key   := 2;
 Pair.Value := 7;
 PriorityList.Add(Pair);

 Pair.Key   := 1;
 Pair.Value := 2;
 PriorityList.Add(Pair);

 case Checkbox1.Checked of
      true  : PriorityList.Sort;
      false : PriorityList.Sort(PairComparer);
 end;

 ListBox1.Clear;
 for iLoop :=  0 to PriorityList.Count-1 do
     ListBox1.Items.Add(Format('Key : %d , Value : %d',[PriorityList[iLoop].Key,PriorityList[iLoop].Value]));

结束;

最佳答案

这种类型的默认比较器是相当任意的。编译器不使用任何有关记录组成的知识。您当然没有告诉它您希望哪个成员作为主排序键。所以它可以自由地做它想做的事。

在 32 位中,8 字节记录的默认比较器是通过调用类似 CompareMem 的函数来实现的。因此字节按地址升序进行比较。因此,关键更加重要。

在 64 位下,默认比较器将类型视为无符号 64 位整数,因此字节按递减地址顺序进行比较,这是小尾​​数法。所以值(value)就更显着了。

相关代码位于Generics.Defaults的实现部分:

function Comparer_Selector_Binary(info: PTypeInfo; size: Integer): Pointer;
begin
  case size of
    // NOTE: Little-endianness may cause counterintuitive results,
    // but the results will at least be consistent.
    1: Result := @Comparer_Instance_U1;
    2: Result := @Comparer_Instance_U2;
    4: Result := @Comparer_Instance_U4;
    {$IFDEF CPUX64}
    // 64-bit will pass const args in registers
    8: Result := @Comparer_Instance_U8;
    {$ENDIF}
  else
    Result := MakeInstance(@Comparer_Vtable_Binary, size);
  end;
end;

最重要的是,每当您希望对记录进行排序时,您都需要提供一个真正的比较器。只有内置的数字和字符串类型才有明确定义的有序比较器。

关于delphi - 使用默认排序在 64 位与 32 位中对 TList<TPair<Integer,integer>> 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22380181/

相关文章:

json - 嵌套 JSON 对象

ios - 如何在 Xcode 中调试 Delphi iOS FireMonkey 应用程序?

java - 使用泛型进行选择排序

python - 在 Maya 中使用 .NET

delphi - ANTLR4 的 Delphi 语法问题

java - JNA-映射 Delphi 函数

java - Java 中的泛型

java - 显式类型参数

c++ - unsigned short 和 signed short 比较奇怪的行为

.net - 64 到 32 位互操作 - 如何?