2014-03-13 1 views
8

32 비트에서 64 비트로 컴파일 할 때 TPair의 기본 정렬간에 차이점이있는 것으로 보입니다. 32 비트 미만에서는 기본 정렬이 64 비트에서 쌍의 키를 정렬하는 것처럼 동작하며 Value별로 정렬됩니다. 이것이 예상 되는가, 또는 나는 무엇인가 놓치고 있는가?기본 정렬을 사용하여 TList <TPair <정수, 정수 >>를 64 비트에서 32 비트로 정렬

테스트 델파이 XE2하는 VCL 응용 프로그램에서 갱신 4. 화면 상에 버튼, 체크 박스와리스트 박스를 드롭

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

다음 버튼의 OnClick하고 실행에 아래의 코드를 삽입 할 경우 다음과 같은 종류를 선언 사용 . 32 비트 미만에서는 기본 정렬을 사용하여 쌍을 키 (예 : 1,2,3,4,5,6)로 나열합니다. 64 비트 미만에서는 쌍 (pair)이 값 (즉, 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])); 

end;

+2

'사례 개 중'이라고 쓰지 마십시오. 그냥 일반 if 문을 사용하십시오. 방법이 더 읽기 쉽습니다. –

+0

각자 자신에게. – Paul

답변

6

이러한 유형의 기본 비교자는 상당히 임의적입니다. 컴파일러는 레코드 구성에 대한 지식을 사용하지 않습니다. 어떤 멤버를 기본 정렬 키로 사용할지 확실히 말하지 않았습니다. 따라서 원하는 것을 자유롭게 할 수 있습니다.

32 비트에서 8 바이트 레코드의 기본 비교자는 CompareMem과 같은 기능을 호출하여 구현됩니다. 따라서 바이트는 주소의 증가 순서로 비교됩니다. 따라서 열쇠가 더 중요합니다.

64 비트 미만에서는 기본 비교자가 형식을 부호없는 64 비트 정수로 처리하므로 바이트가 감소하는 주소 순서로 비교됩니다. 이는 리틀 엔디안입니다. 그리고 그 가치는 더욱 중요합니다.

관련 코드는 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; 

결론은 당신이 레코드를 정렬 할 때마다 당신이 진짜 비교자를 제공해야한다는 것입니다. 내장 된 숫자 및 문자열 유형에만 잘 정렬 된 비교자를 정의합니다.

+2

"내장 된 숫자 및 문자열 유형 만 정렬 된 비교자를 잘 정의합니다." TOrdinalStringComparer.Compare를 살펴 본다면 그렇게 말하지 않을 것입니다.) –

+0

David에게 감사드립니다. 이것은 내가 평범하지 않은 데이터의 기본 정렬에 "의존"한 유일한 인스턴스 중 하나였습니다. 교훈을 얻었습니다. 항상 비교자를 지정하십시오 ... – Paul