2013-07-22 3 views
2

У меня есть этот простой кодВложенные функции компаратора не удается TStringList.CustomSort с использованием Delphi XE3 64-битную

procedure TForm2.btn1Click(Sender: TObject); 
var s : TStringList; 

    function compare(s : TStringList; i1, i2 : integer) : integer; 
    begin 
    result := CompareText(s[i1], s[i2]); 
    end; 

begin 
    s := TStringList.Create; 
    try 
    s.add('s1'); 
    s.add('s2'); 
    s.add('s3'); 
    s.CustomSort(@compare); 
    finally 
    s.free; 
    end; 
end; 

Он работает, как ожидалось, когда я скомпилировать его как 32-бит, но я получаю нарушение прав доступа при использовании 64- немного. Для сравнения 64-битной версии, s = nil. i2 = some random value;

Он также работает, как и ожидалось, для цели Win64, если я извлекаю функцию compare за пределами функции btn1Click.

Это ошибка System.Classes, есть ли способ исправить?

+0

Он работает, как и ожидалось, если функция сравнения из btn1Click – TheHorse

+0

не оставлять комментарии - отредактируйте quesiton вместо этого. –

+2

Я уверен, что это обман несколько раз за –

ответ

4

Локальные вложенные функции НЕ ДОЛЖНЫ назначаться процедурным переменным (в частности, НЕ ДОЛЖНЫ быть переданы в качестве параметров процедурной переменной).

http://docwiki.embarcadero.com/RADStudio/XE4/en/Procedural_Types - поиск "вложенных".

Причина проста: локальные функции должны расположить их стек так, чтобы они получали доступ к всем стековым кадрам своих верхних функций (родителей). Однако эти фреймы стека не могут существовать, когда эти функции перескакивают без предварительного вызова всей цепочки своих родительских функций по одному. И это «синее» погружение - это именно то, что происходит при прохождении своего адреса за пределами руководителей, которые не обращают внимания на эту конкретную вызывающую цепочку. Это похоже на вызов виртуальных методов какого-либо объекта без VMT, имеющих ссылку на родительские классы, и без самонаведения на правильный VMT.

Ошибка в том, что такой код не работает в win64.

Ошибка в том, что она даже компилируется в win32 или win64 независимо.

Когда Delphi исправит ошибку, он больше не будет компилировать такой код, если вы не сделаете compare надлежащей глобальной функцией, как это должно быть.

+6

Он работал в Win32, потому что компилятор был достаточно умен, чтобы удалить скрытый дополнительный указатель указателя стека (EBP), если локальная процедура не имеет доступа к чему-либо из стека внешней процедуры. У компилятора Win64 больше нет этой логики и всегда добавляется скрытый параметр. –