Использование переменной счетчика после цикла FOR-Loop

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
Rang
новенький
Сообщения: 12
Зарегистрирован: 15.10.2015 14:44:16

Использование переменной счетчика после цикла FOR-Loop

Сообщение Rang »

Столкнулся с проблемой при переходе с Delphi 2007 на FPC.

Есть код:

Код: Выделить всё

for i := 0 to 10 do
  Continue;
Writeln('Result: ', i);


На Delphi 2007:

Код: Выделить всё

Result: 11


На FPC:

Код: Выделить всё

Result: 10


То есть, в Delphi в конце цикла идет увеличение переменной и потом выход из него, в FPC сразу выход из цикла.
Все бы логично, и Delphi предупреждает, что переменная 'i' может быть неопределенной после цикла.

Суть в том, что есть крупный проект, в котором часто использовали такой трюк Delphi и сейчас возникла проблема с поиском и устранением этих трюков на FPC.
Код выше, при компиляции в Delphi, выдает предупреждение: W1037 Variable 'i' may be undefined after loop.
А FPC никаких предупреждений не выводит и по сути отлов таких мест становится затруднительным.

Но иногда и Delphi чудит, видоизменяем код на такой:

Код: Выделить всё

for i := 0 to 10 do
  if i < 15 then
    Continue
  else
    Break;
Writeln('Result: ', i);

... теперь и Delphi не видит в этом коде проблем. Предупреждения нет.

Есть ли возможность что-то включить в FPC, чтобы эти ошибки появились?
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение wavebvg »

Хочу сильно Вас расстроить. При штатном выходе из цикла по условию (без break или exit) значение неопределенно.
Это связано с тем, что при оптимизации, компилятор может использовать вместо счетчика регистр процессора, а при выходе из цикла — просто сбросить значение (pop/push).
Компилятор не всегда догадывается, что вы от него хотели, поэтому при использовании break, как в примере, предупреждений не делает. При этом, гарантий, что скомпилированный код будет всегда корректно работать — нет.
Если проект крупный, то вычитать и исправить (ну или пометить как верное, отключив на этом участке проверку) все предупреждения компилятора — дело святое.
Последний раз редактировалось wavebvg 04.09.2018 10:40:34, всего редактировалось 1 раз.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

Rang писал(а):Есть ли возможность что-то включить в FPC, чтобы эти ошибки появились?

Это вряд ли... Потому что это не ошибка, а стандартное поведение. Delphi (как и паскаль) изначально был рассчитан на эксплуатацию контингентом, квалификация которого ниже плинтуса. :-) И такие предупреждения - это нормальное для него поведение, потому что это обучение программированию. У FPC ориентация несколько другая, именно поэтому он таких предупреждений и не даёт.
Rang писал(а):... Delphi предупреждает, что переменная 'i' может быть неопределенной после цикла.

FPC в своём руководстве точно так же оговаривает поведение переменной цикла:
• The value of the loop variable is undefined after a loop has completed or if a loop is not executed at all. If the loop was terminated prematurely with an exception or a break statement,
the loop variable retains the value it had when the loop was exited.

но кто же читает руководства? :-D
Если вкратце Break\Exit - это гарантия того, что переменная цикла сохраняет своё значение. И менно потому, что цикл не выполнен и надо проанализировать его составляющие. Во всех остальных случаях полагаться на переменную нельзя.
Что пишут в Delphi по этому поводу я никогда не интересовался, однако поведение FPC, что Вы и показали, вполне логично. А вот Delphi как раз не очень, т.к. изменять переменную цикла после работы цикла бессмысленно.
Таким образом, Ваш проект основывается на неопределённости. И Вы ничего по этому поводу предпринимать не хотите, даже несмотря на предупреждения компилятора Delphi. ;-)
По этому поводу лучше всего поговорить с разработчиками компилятора, а не с его пользователями (а мы тут, как раз такими пользователями, за редким исключением, и являемся). Вполне возможно, что есть определённый алгоритм поведения переменной и лучше опираться на него, если Вы непременно хотите делать сюрпризы пользователям Вашей программы. ;-)
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>Если вкратце Break\Exit - это гарантия того, что переменная цикла сохраняет своё значение.
Чтобы воспользоваться этой гарантией надо приложить дополнительные усилия чтобы быть уверенным что цикл закончился по Break. Очень странная ремарка - лучше не беря ее во внимание считать переменную всегда неопределенной.

ИМХО компилятор должен ругаться на попытку использования переменной без инициализации. Цикл не является способом инициализации переменной
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

zub писал(а):Чтобы воспользоваться этой гарантией надо приложить дополнительные усилия чтобы быть уверенным что цикл закончился по Break.

Поэтому и не стоит злоупотреблять костылями для попыток вытрясти переменную цикла вне цикла. Я ведь об этом и написал. ;-)
sign
энтузиаст
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Сообщение sign »

Когда мне, ну, ужасть, как надо переменную цикла за циклом, я использую while ... do.
Rang
новенький
Сообщения: 12
Зарегистрирован: 15.10.2015 14:44:16

Сообщение Rang »

Спасибо всем за комментарии.
Уже переделал большую часть таких циклов на правильные, не зависящие от компилятора.

Согласен с тем, что если нужна переменная после\вне цикла - то проще сделать это через while..do.
Ответить