Паскаль считает назад, а не вверх?так странно - PullRequest
0 голосов
/ 27 мая 2018

http://rextester.com/OXRFB95557

Часы показывают, что счетчик j не падает вверх ... есть идеи, почему?спасибо

program NEACardTrick;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Math;

type
  Tcards = array[1..21] of string;    
var
   cards: Tcards = ('H A', 'H 2', 'H 3', 'H 4', 'H 5', 'H 6', 'H 7',
             'S A', 'S 2', 'S 3', 'S 4', 'S 5', 'S 6', 'S 7',
             'D A', 'D 2', 'D 3', 'D 4', 'D 5', 'D 6', 'D 7');
   shuffledCards:Tcards;
   i,j,y, x: integer;


function get_cards(var cards: array of string): Tcards;    
begin    
  y := 1;
  Repeat
    Randomize;
    x := RandomRange(1,21);
    If cards[x] <> 'Done' then
    begin
      shuffledCards[y] := cards[x];
      y := y + 1;
      cards[x] := 'Done';
    end    
  Until y >= 21;        
  result := shuffledCards;
end;

procedure PrintCards(var shuffledCards: Tcards);
var
  j: integer;
begin
  for j := 1 to 21 do
    writeln(shuffledCards[j]);
end;

begin    
  get_cards(cards);
  PrintCards(shuffledCards);
  readln;
end.

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Ваше наблюдение в Delphi 7 относительно переменной j: integer в procedure PrintCards() точно так же, как это показано в часах отладчика.Однако, будьте уверены, цикл for работает правильно.

В вашем коде вы дали j две обязанности: 1) действовать как элемент управления цикла и 2) действовать как индекс дляshuffledCards[] array.

Компилятор преобразует ваш Delphi-код в максимально эффективный (но, конечно, правильный) машинный код.Организация цикла таким образом, что обнаружение ZF (нулевой флаг) в качестве условия завершения цикла вместо явного сравнения со значением const является одним из способов повышения эффективности.Следовательно, обязанность 1) решается с помощью управления с уменьшающимся контуром, в этом случае зарегистрируйте esi (см. Разборку ниже).

Для второй обязанности регистр esi не может быть использован, поскольку он считает в неправильном направлении.Итак, другой регистр ebx используется для дежурства 2).Он настроен как указатель на первый элемент массива (элемент с индексом 1).Затем в каждом раунде цикла ebx увеличивается, чтобы указывать на следующий элемент.

Вот разборка процедуры PrintCards():

Project2.dpr.38: begin
0040876C 53               push ebx
0040876D 56               push esi
0040876E 57               push edi
0040876F 8BF8             mov edi,eax

Project2.dpr.39: for j := 1 to 21 do
00408771 BE15000000       mov esi,$00000015    // Initialize loop control

00408776 8BDF             mov ebx,edi          // set up pointer to array
Project2.dpr.40: writeln(shuffledCards[j]);
00408778 A160934000       mov eax,[$00409360]  // loop start
0040877D 8B13             mov edx,[ebx]
0040877F E8B4B8FFFF       call @WriteOLString
00408784 E8CFA5FFFF       call @WriteLn
00408789 E8B69EFFFF       call @_IOTest

0040878E 83C304           add ebx,$04          // advance array element pointer
Project2.dpr.39: for j := 1 to 21 do
00408791 4E               dec esi              // decrement loop control
00408792 75E4             jnz -$1c             // jump if not zero to loop start

Project2.dpr.41: end;
00408794 5F               pop edi
00408795 5E               pop esi
00408796 5B               pop ebx
00408797 C3               ret

Поместите точку останова на линию39 а потом беги.Когда остановитесь в строке 39, вызовите представление CPU (View - Debug Windows - CPU или Ctrl-Alt-C).Затем выполните один шаг (F8) и проследите за изменениями регистров, чтобы увидеть для себя

Часы отладчика для j показывают значение esi, поэтому вы видите, что значение снижается с 21 до 1(на самом деле вы можете видеть, что финальный 0 появляется сразу после последнего выполнения dec esi).

0 голосов
/ 27 мая 2018

Ваш диагноз неверен.Индексная переменная считает в этом цикле.

Если переменная цикла не используется, компилятор может оптимизировать счетчик цикла для запуска в любом порядке, который он выберет.Но в вашем цикле используется переменная индекса, поэтому она должна увеличиваться.

...