операторов - delphi record case statement




Как компилятор обрабатывает заявления о случаях? (2)

В документации по деловым заявлениям говорится:

Каждое значение, представленное caseList, должно быть уникальным в заявлении case;

И пример, показанный,

case I of
  1..5: Caption := 'Low';
  6..9: Caption := 'High';
  0, 10..99: Caption := 'Out of range';
else
  Caption := ;
end

эквивалентно вложенному условному:

if I in [1..5] then
  Caption := 'Low';
else if I in [6..10] then
  Caption := 'High';
else if (I = 0) or (I in [10..99]) then
  Caption := 'Out of range'
else
  Caption := ;

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

Теперь я знаю часть

где selectorExpression - любое выражение порядкового типа, меньшего 32 бит

противоречит свойствам множеств, как упоминалось ей под множествами:

Базовый тип может иметь не более 256 возможных значений, а их порядки должны находиться между 0 и 255

Меня действительно беспокоит то, почему возникает необходимость иметь уникальные значения в caseList. Если это эквивалентно оператору if , второе значение будет просто не проверено, потому что компилятор уже нашел предыдущее соответствие?


деловая ситуация
Компилятор предпочитает преобразовать оператор case в таблицу переходов.
Для того, чтобы сделать возможными дубликаты меток, нельзя.

Кроме того, компилятор не должен проверять утверждения case в том порядке, в котором вы их объявили. По соображениям оптимизации он будет изменять порядок этих элементов по своему усмотрению; поэтому, даже если он не использует таблицу переходов, он все равно не может допускать дублирование ярлыков case.

Именно по этой же причине (и чтобы программисты мысленно здравомысляли), что оператор case не допускает провалов.

если утверждение
A (серия), если операторы обрабатываются в том порядке, в котором они объявлены.
Компилятор будет проверять их один за другим (и выпрыгивать, когда это необходимо).
Если оператор if не содержит дубликатов, код будет выполнять те же действия, что и эквивалентный оператор case, но сгенерированный код, скорее всего, будет отличаться.
Если утверждения никогда не преобразуются в таблицы перехода.

о наборах
Набор причин ограничен 256 элементами - каждый элемент в наборе занимает один бит пространства.
256 бит = 32 байта.
Разрешить более 256 элементов в наборе увеличит представление в памяти слишком сильно, затрудняя производительность.

Оператор case не использует множества, он просто использует логику набора в своей семантике.


В документации содержится конкретный оператор case, который эквивалентен конкретному оператору if .

В общем случае любой оператор case может быть переписан как оператор if с использованием того же подхода. Однако обратное неверно.

В документации используется эквивалентный оператор if для объяснения логического поведения (или семантики ) оператора case . Это не представление того, что делает компилятор внутри себя.

Как компилятор обрабатывает регистр case?

Прежде всего, есть два аспекта этого вопроса.

  • Семантически компилятор должен обрабатывать оператор case, как указано в документации. Это включает:
    • Обеспечение того, чтобы значения каждой записи caseList могли быть оценены во время компиляции.
    • Обеспечение уникальности записей caseList .
    • В зависимости от того, какая запись caseList соответствует, вызывается соответствующий caseList-statement.
    • Если никакие записи caseList не совпадают, вызывается выражение else.
  • Тем не менее, компилятор имеет право оптимизировать реализацию, поскольку он считает нужным, если оптимизированный байтовый / машинный код логически эквивалентен.
    • Ответ Йохана описывает общие оптимизации: списки переходов и переупорядочение.
    • Их гораздо проще применять, учитывая строгую семантику.

Меня действительно беспокоит то, почему возникает необходимость иметь уникальные значения в caseList .

Для устранения двусмысленности требуется уникальность. Какой caseList-оператор следует использовать, если более одного совпадения?

  • Он может вызывать первое совпадение caseList-statement и игнорировать остальные. (Оператор CASE SQL Server ведет себя следующим образом.) Также см. [1] ниже.
  • Это можно было бы назвать всеми. (Если я правильно помню, язык программирования MANTIS использует эту семантику для своей версии case case.)
  • Он может сообщать об ошибке, требующей от программиста устранения неоднозначности caseList . (Проще говоря, это то, что требует спецификация Delphi. Многие другие языки используют один и тот же подход. Взаимодействие с этим непроизводительно, поскольку этот выбор вряд ли будет значительным препятствием.)

Если это эквивалентно оператору if, второе значение будет просто не проверено, потому что компилятор уже нашел предыдущее соответствие.

[1] Я хотел бы отметить, что это может сделать код гораздо труднее читать. Это поведение «нормально» при использовании магических литералов, но при использовании константных идентификаторов становится опасным. Если две разные константы имеют одинаковое значение, сразу не станет очевидным, что последний caseList-оператор, в котором также совпадение caseList , не будет вызываться. Кроме того, case- запросы будут подвержены изменению поведения из-за простого переупорядочения списка caseList .

const
  NEW_CUSTOMER = 0;
  EDIT_CUSTOMER = 1;
  ...
  CANCEL_OPERATION = 0;

case UserAction of
  NEW_CUSTOMER : ...;
  EDIT_CUSTOMER : ...;
  ...
  CANCEL_OPERATION : ...; { Compiler error is very helpful. }
end;

Противоречие со свойствами множеств

Нет никакого противоречия. Тот факт, что каждое значение caseList должен быть уникальным, никоим образом не означает, что он должен «обрабатываться как набор». Это ваше неправильное предположение. Аналогичные предположения других людей также неверны.

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







switch-statement