Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Компилятор Delphi Xe создаёт не корректный код


Автор: IDARKShadowI 11.10.2011, 16:08
При разработке большого проекта столкнулся со следующей проблемой, вот тестовый проект отображающий её:

Код

program Test;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TError = class
  private
    function Add(FromV, ToV: Integer): Integer;
    function Check(Row: Integer; Val: Byte): Boolean;
    function Operation(Index: Integer; Func: TFunc<Integer,Integer>): Integer;
  public
    function Run(Count: Integer): Integer;
  end;

function TError.Add(FromV, ToV: Integer): Integer;
var
  i: Integer;
  res: Integer;
  func: TFunc<Integer,Integer>;
begin
  res := 0;
  func :=
    function(data: Integer): Integer
    begin
      if Check(i, 127) then
        Result := data;
    end;

  for i := FromV to ToV do
    res := Operation(i, func);

  Result := res;
end;

function TError.Check(Row: Integer; Val: Byte): Boolean;
begin
  Result := True;
end;

function TError.Operation(Index: Integer; Func: TFunc<Integer, Integer>): Integer;
begin
  if Assigned(Func) then
    Result := Func(Index);
end;

function TError.Run(Count: Integer): Integer;
begin
  Result := Add(0, Count);
end;

begin
  try
    with TError.Create do
    begin
      WriteLn('Count: 32766; Run: ', Run(32766));
      WriteLn('Count: 32768; Run: ', Run(32768));
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.


При запуске получаем:

Код

Count: 32766; Run: 32766
Count: 32768; Run: 0


То есть, во втором случае цикл не выполняется ни разу.
А вот код, который создаёт компилятор для цикла:

Код

0040F8D0 FF400C           inc dword ptr [eax+$0c]
Test.dpr.32: for i := FromV to ToV do
0040F8D3 8B45E0           mov eax,[ebp-$20]
0040F8D6 8B400C           mov eax,[eax+$0c]
0040F8D9 663B45E6         cmp [U]ax[/U],[ebp-$1a]
0040F8DD 7ED7             jle $0040f8b6 {переход на тело}


Тут видно, что сравнение идёт с 16-ти битным целым, хотя должно быть 32 бита.

Запостил отчёт на QualityCentral:

http://qc.embarcadero.com/wc/qcmain.aspx?d=99909

Проблему можно обойти выносом анонимной функции в метод, вот так:

Код

  TError = class
  private
    _i: integer;
    function Add(FromV, ToV: Integer): Integer;
    function Check(Row: Integer; Val: Byte): Boolean;
    function Operation(Index: Integer; Func: TFunc<Integer,Integer>): Integer;
    function AFunc(AData: Integer): Integer;
  public
    function Run(Count: Integer): Integer;
  end;

function TError.Add(FromV, ToV: Integer): Integer;
var
  i: Integer;
  res: Integer;
  func: TFunc<Integer,Integer>;
begin
  res := 0;

  for i := FromV to ToV do
    res := Operation(i, AFunc);

  Result := res;
end;

function TError.AFunc(AData: Integer): Integer;
begin
  if Check(_i, 127) then
    Result := AData;
end;

function TError.Operation(Index: Integer; Func: TFunc<Integer, Integer>): Integer;
begin
  _i := Index;
  if Assigned(Func) then
    Result := Func(Index);
end;


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)