DELPHI - дополнительные точки с запятой, кроме блоков, какого-либо назначения? Необязательная точка с запятой перед исключением или концом. Что лучше с или без? - PullRequest
0 голосов
/ 18 февраля 2020

Я работаю в приложении с некоторыми отклонениями от точки с запятой в Delphi 10.3.3. Я читал, что некоторые точки с запятой необязательны, в зависимости от компилятора, когда не между утверждениями. В течение многих лет я думал, что это ошибка в компиляторе Delphi, позволяющая это сделать. Я вижу, как приложение компилируется, если они были отброшены до какого-либо оператора окончания блока.

Используется ли точка с запятой между [кроме] и [концом] для какой-либо цели в коде, например, для более быстрого выполнения или броска какое-то исключение по умолчанию или какое-то другое назначение Может ли это привести к случайным ошибкам компиляции или времени выполнения?

Оставляет ли точка с запятой за последней строкой до конца или кроме ускорения времени выполнения? Является ли один способ более подверженным ошибкам, чем другой, или подвержен случайным ошибкам компиляции или выполнения?

Вот код, который можно перетащить в любой тестовый проект с формой, имеющей поле редактирования, кнопку и блокнот, созданный с настройками по умолчанию для перетаскивания.

function TForm1.isThisUseful(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except
    ;
  end;
  result := (i > 0)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if isThisUseful(Edit1.Text)
  then
    Memo1.Text := 'Yes, it is useful'
  else
    Memo1.Text := 'This is a waste of time.'
end;

Ответы [ 4 ]

4 голосов
/ 18 февраля 2020

tl; dr: без разницы.

try
  // do stuff
except
  ;
end;

Эту точку с запятой можно удалить. Это абсолютно не имеет никакого эффекта. Это не приносит пользы и не приносит вреда (за исключением, возможно, того, что исходный код выглядит странно, чего следует избегать 1 ).

begin
  DoThis;
  DoThat;
end;

Поскольку в Delphi , точки с запятой в отдельных операторах, последняя точка с запятой перед end не обязательна. Это абсолютно не имеет никакого эффекта. В основном это дело вкуса, хотите вы этого или нет (и лично у меня это иногда бывает, а иногда нет).

Одно из преимуществ использования этой точки с запятой может заключаться в том, что вы затем можете перемещать или копировать эту строку, без изменения, в другое место, где не является последним оператором в своем блоке. Аналогично, вы также можете вставить новый оператор сразу после этой строки кода, не добавляя точку с запятой. ИМХО, это очень незначительные преимущества; нетрудно добавить точку с запятой, если и когда это станет необходимым.

Бонусный комментарий: Однако result := (i > 0) выглядит для меня странно. Я бы ожидал Result := i > 0, без лишних скобок. (Это может быть потому, что я программировал на Delphi почти ежедневно более 20 лет.)

Бонусный комментарий 2: Обратите внимание, что компилятор с радостью принимает

begin
  DoThis;;
  DoThat;
end;

. Он просто игнорирует лишние точки с запятой. Но приведенный выше фрагмент выглядит для меня очень безобразно, и мне всегда странно, что разработчики предпочитают фиксировать код, не читая его сначала.

Бонусный комментарий 3: Кен Бурасса написал ответ , приводящий пример сценария, в котором наличие или отсутствие точки с запятой влияет на программы. Но есть еще более страшный пример:

case i of
  0:
    DoA;
  1:
    DoB;
  2:
    if j = 0 then
      DoC{;}
else
  DoD;
end;

1 В этом случае вы также можете утверждать, что точка с запятой служит цели: она «подсвечивает» пустое except блок, что делает его немного легче обнаружить быстро. Следовательно, это может быть преднамеренным. Но можно утверждать, что лучший способ выделить это - добавить комментарий типа // Do nothing или // Just carry on. (И во многих, если не в большинстве случаев, пустые блоки except вообще не годятся.)

2 голосов
/ 19 февраля 2020

Я подумал, что попробую некоторые измерения, используя линейный таймер Quality Suite NexusDB в этой тестовой программе D7:

{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W+,X+,Y+,Z1}
program semicolontest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function isThisUseful1(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except
    ;
  end;
  result := (i > 0)
end;

function isThisUseful2(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except

  end;
  result := (i > 0)
end;

var
  Input : String[20];
  i : Integer;
  Res : Boolean;

begin

   Input := 'abcdefg';

   writeln('Starting');
   for i := 1 to 1000000 do begin
     Res := isThisUseful1(Input);
     Res := isThisUseful2(Input);
   end;
   writeln('Done');
   // readln;
end.

, которая содержит две версии функции isThisUseful из вопроса, один с, а другой без точки с запятой в блоке except. Результаты выполнения этого кода (с извинениями за слегка искаженный макет) следующие:

Line    Total Time  Hit Count   Source
1       -   {$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W+,X+,Y+,Z1}
2       -   program semicolontest;
3       -   
4       -   {$APPTYPE CONSOLE}
5       -   
6       -   uses
7       -     SysUtils;
8       -   
9       -   function isThisUseful1(this : string): boolean;
10      -   var
11      -     i: Integer;
12  2.807175    1,000,000   begin
13  0.761388    1,000,000     result := false;
14  2.133202    1,000,000     try
15  1.403061    1,000,000       if this = ''
16      -       then
17      -         i := 0
18      -       else
19  0.826841    1,000,000         i := 1
20      -     except
21      -       ;
22      -     end;
23  0.735419    1,000,000     result := (i > 0)
24      -   end;
25      -   
26      -   function isThisUseful2(this : string): boolean;
27      -   var
28      -     i: Integer;
29  1.260030    1,000,000   begin
30  0.782293    1,000,000     result := false;
31  0.894420    1,000,000     try
32  0.820860    1,000,000       if this = ''
33      -       then
34      -         i := 0
35      -       else
36  0.873424    1,000,000         i := 1
37      -     except
38      -   
39      -     end;
40  0.778922    1,000,000     result := (i > 0)
41      -   end;
42      -   
43      -   var
44      -     Input : String[20];
45      -     i : Integer;
46      -     Res : Boolean;
47      -   
48  1.167140    1   begin
49      -   
50  0.000036    1      Input := 'abcdefg';
51      -   
52  0.641347    1      writeln('Starting');
53  0.000026    1      for i := 1 to 1000000 do begin
54      -        Res := isThisUseful1(Input);
55      -        Res := isThisUseful2(Input);
56  0.669066    1,000,000      end;
57  0.402661    1      writeln('Done');
58      -      // readln;
59      -   end.
60      -   

Обратите внимание, что для строки 21 не записывается время, точка с запятой в блоке try ...except для простого причина того, что, как и ожидалось, код для него не генерируется.

Для полноты ниже приведены разборки isThisUseful1 и isThisUseful2

isThisUseful1:

Address Bytes   Text    Block #
00408620h       [semicolontest.dpr.12] begin    
00408620h   55        push ebp  1
00408621h   8BEC          mov ebp, esp  1
00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
00408626h   53        push ebx  1
00408627h   56        push esi  1
00408628h   57        push edi  1
00408629h   8945FC        mov [ebp-04h], eax    1
0040862Ch   8B45FC        mov eax, [ebp-04h]    1
0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
00408634h   33C0          xor eax, eax  1
00408636h   55        push ebp  1
00408637h   689A864000        push offset @@6   1
0040863Ch   64FF30        push fs:[eax] 1
0040863Fh   648920        mov fs:[eax], esp 1
00408642h       [semicolontest.dpr.13] result := false; 
00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
00408646h       [semicolontest.dpr.14] try  
00408646h   33C0          xor eax, eax  1
00408648h   55        push ebp  1
00408649h   6872864000        push offset @@3   1
0040864Eh   64FF30        push fs:[eax] 1
00408651h   648920        mov fs:[eax], esp 1
00408654h       [semicolontest.dpr.15] if this = '' 
00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
00408658h   7507          jnz @@1   1
0040865Ah       [semicolontest.dpr.17] i := 0   
0040865Ah   33C0          xor eax, eax  2
0040865Ch   8945F4        mov [ebp-0Ch], eax    2
0040865Fh   EB07          jmp @@2   2
00408661h       [semicolontest.dpr.19] i := 1   
00408661h       @@1:    
00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
00408668h       @@2:    
00408668h   33C0          xor eax, eax  4
0040866Ah   5A        pop edx   4
0040866Bh   59        pop ecx   4
0040866Ch   59        pop ecx   4
0040866Dh   648910        mov fs:[eax], edx 4
00408670h   EB0A          jmp @@4   4
00408672h       @@3:    
00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
00408677h       [semicolontest.dpr.21] ;    
00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
0040867Ch       @@4:    
0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
00408680h   0F9F45FB          setnle [ebp-05h]  6
00408684h   33C0          xor eax, eax  6
00408686h   5A        pop edx   6
00408687h   59        pop ecx   6
00408688h   59        pop ecx   6
00408689h   648910        mov fs:[eax], edx 6
0040868Ch   68A1864000        push offset @@7   6
00408691h       @@5:    
00408691h   8D45FC        lea eax, [ebp-04h]    7
00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
00408699h   C3        ret   7
0040869Ah       @@6:    
0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
0040869Fh   EBF0          jmp @@5   8
004086A1h       @@7:    
004086A1h   8A45FB        mov al, [ebp-05h] 9
004086A4h       [semicolontest.dpr.24] end; 
004086A4h   5F        pop edi   9
004086A5h   5E        pop esi   9
004086A6h   5B        pop ebx   9
004086A7h   8BE5          mov esp, ebp  9
004086A9h   5D        pop ebp   9
004086AAh   C3        ret   9

isThisUseful2:

Address Bytes   Text    Block #
00408620h       [semicolontest.dpr.12] begin    
00408620h   55        push ebp  1
00408621h   8BEC          mov ebp, esp  1
00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
00408626h   53        push ebx  1
00408627h   56        push esi  1
00408628h   57        push edi  1
00408629h   8945FC        mov [ebp-04h], eax    1
0040862Ch   8B45FC        mov eax, [ebp-04h]    1
0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
00408634h   33C0          xor eax, eax  1
00408636h   55        push ebp  1
00408637h   689A864000        push offset @@6   1
0040863Ch   64FF30        push fs:[eax] 1
0040863Fh   648920        mov fs:[eax], esp 1
00408642h       [semicolontest.dpr.13] result := false; 
00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
00408646h       [semicolontest.dpr.14] try  
00408646h   33C0          xor eax, eax  1
00408648h   55        push ebp  1
00408649h   6872864000        push offset @@3   1
0040864Eh   64FF30        push fs:[eax] 1
00408651h   648920        mov fs:[eax], esp 1
00408654h       [semicolontest.dpr.15] if this = '' 
00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
00408658h   7507          jnz @@1   1
0040865Ah       [semicolontest.dpr.17] i := 0   
0040865Ah   33C0          xor eax, eax  2
0040865Ch   8945F4        mov [ebp-0Ch], eax    2
0040865Fh   EB07          jmp @@2   2
00408661h       [semicolontest.dpr.19] i := 1   
00408661h       @@1:    
00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
00408668h       @@2:    
00408668h   33C0          xor eax, eax  4
0040866Ah   5A        pop edx   4
0040866Bh   59        pop ecx   4
0040866Ch   59        pop ecx   4
0040866Dh   648910        mov fs:[eax], edx 4
00408670h   EB0A          jmp @@4   4
00408672h       @@3:    
00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
00408677h       [semicolontest.dpr.21] ;    
00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
0040867Ch       @@4:    
0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
00408680h   0F9F45FB          setnle [ebp-05h]  6
00408684h   33C0          xor eax, eax  6
00408686h   5A        pop edx   6
00408687h   59        pop ecx   6
00408688h   59        pop ecx   6
00408689h   648910        mov fs:[eax], edx 6
0040868Ch   68A1864000        push offset @@7   6
00408691h       @@5:    
00408691h   8D45FC        lea eax, [ebp-04h]    7
00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
00408699h   C3        ret   7
0040869Ah       @@6:    
0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
0040869Fh   EBF0          jmp @@5   8
004086A1h       @@7:    
004086A1h   8A45FB        mov al, [ebp-05h] 9
004086A4h       [semicolontest.dpr.24] end; 
004086A4h   5F        pop edi   9
004086A5h   5E        pop esi   9
004086A6h   5B        pop ebx   9
004086A7h   8BE5          mov esp, ebp  9
004086A9h   5D        pop ebp   9
004086AAh   C3        ret   9

(я сам пытался сравнить их, пытаясь сравнить их, и не собирался тратить свое время, прогоняя их мимо BeyondCompare).

В любом случае, я думаю, что это показывает, что, как указано мной и другими, компилятор не генерирует код для строки, содержащей только точку с запятой в блоке try...except, и не должен делать это нигде, хотя, как отмечалось, существуют случаи, когда наличие или в противном случае точка с запятой изменяет семантику кода и, следовательно, сгенерированный код.

0 голосов
/ 01 марта 2020

Я ценю все отзывы на этот пост. Я хотел бы суммировать некоторые моменты.

Точки с запятой меняют способ компиляции приложения. Поэтому размер приложения может меняться на минуту. Таким образом, в приложении это, по-видимому, жесткий терминатор или терминатор с переключением между ветвями. Тем не менее, это, вероятно, должно быть в конце каждой попытки, кроме конца; перед каждым исключением или, наконец, и в конце каждого L oop, независимо от того, что следует, чтобы гарантировать, что компиляция чиста и всегда одинакова.

Но не должно быть проблемы, отсутствующей в if - [конец] перед другим оператором [конец] или как дополнительный элемент внутри места, где нет другого кода. Но, вероятно, лишняя точка с запятой внутри al oop не самая лучшая идея.

0 голосов
/ 19 февраля 2020

В дополнение к ответу Андреаса ...

Существует 1 ситуация, когда вы определенно (или, по крайней мере, скорее всего) не хотите оставлять точку с запятой, и это после "затем ». Следующий код будет показывать «B» в окне сообщения.

procedure TForm3.FormCreate(Sender: TObject);
var
  S : String;
begin
  S := 'A';
  if 1 = 2 then;
    S := 'B';

  ShowMessage(S);
end;

Сверху моей головы, это единственный случай, когда вставка точки с запятой меняет генерацию кода самостоятельно.

...