Объявление переменных уровня блока для веток в delphi - PullRequest
4 голосов
/ 29 июня 2011

В призме Delphi мы можем объявить переменные, которые нужны только в особых случаях.

Например: В призме

 If acondition then
     begin
        var a :Integer;
     end;
    a := 3; //this line will produce error. because a will be created only when the condition is true

Здесь«a» нельзя присвоить 3, потому что оно вложено в ветку.Как мы можем объявить переменную, которая может использоваться только внутри ветви в delphi win32.Таким образом, я могу уменьшить использование памяти, поскольку она создается только в том случае, если выполняется определенное условие;

Если уменьшение использования памяти не является проблемой, какие недостатки у нас есть (или у нас нет)

Ответы [ 6 ]

8 голосов
/ 29 июня 2011

Предпосылка вашего вопроса ошибочна. Вы предполагаете, что в языках, где разрешены переменные уровня блока, программа выделяет и освобождает память для этих переменных, когда элемент управления входит или выходит из области действия этих переменных. Так, например, вы думаете, что когда acondition истинно, программа корректирует стек, чтобы освободить место для переменной a, когда она входит в этот блок. Но ты не прав.

Компиляторы вычисляют максимальное пространство, необходимое для всех объявленных и временных переменных, а затем резервируют столько места при входе в функцию. Выделить это пространство так же просто, как настроить указатель стека; требуемое время обычно не имеет ничего общего с количеством зарезервированного пространства. Суть в том, что ваша идея на самом деле не сэкономит места.

Реальным преимуществом наличия переменных уровня блока является то, что их области действия ограничены.

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

7 голосов
/ 29 июня 2011

Концепция Операторы объявления локальной переменной , как в Java, не поддерживается в Delphi, но вы можете объявить подпроцедуру:

procedure foo(const acondition: boolean);

  procedure subFoo;
  var
    a: integer;
  begin
    a := 3;
  end;

begin
  If acondition then
  begin
    subFoo;
  end;
end;
3 голосов
/ 29 июня 2011

Остерегайтесь, что это может быть только «синтаксический сахар». Компилятор может гарантировать, что вы не используете переменную вне внутренней области видимости, но это не значит, что она может сэкономить память. Переменная может быть размещена в стеке в коде входа процедуры в любом случае, независимо от того, используется ли она на самом деле или нет. AFAIK большинство ABI инициализируют стек при входе и очищают его при выходе. Управление стеком намного более сложным способом во время выполнения функции, включая заботу о различных путях выполнения, может быть даже менее производительным - вместо одной инструкции для резервирования пространства стека вам нужно несколько команд, разбросанных по коду, и обеспечить восстановление стека правильное добавление большего, особенно раскручивание стека из-за исключения, может стать намного более сложным. Если цель состоит в том, чтобы написать «лучший» код из-за лучшей обработки области, чтобы гарантировать, что неправильная переменная не используется в неправильном месте, это может быть полезно, но если вам нужно это как способ экономии памяти, это не может быть правильным способом .

3 голосов
/ 29 июня 2011

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

type TIntegerA = record
  A: Integer;
end;

function varAInteger: TIntegerA;
begin
  Result.A := 0;
end;

// Code using this pseudo-local-variable
if Condition then
  with varAInteger do
  begin
    A := 7; // Works.
  end
else
  begin
    A := 3; // Error, the compiler doesn't know who A is
  end;

Изменить для уточнения этого предложения

Пожалуйста, обратите внимание, что этот вид волшебства не является реальной заменой истинным переменным уровня блока: даже те, которые они, вероятно, размещены в стеке, как и большинство других локальных переменных, компилятор не приспособлен к ним как таковым. Он не будет выполнять те же оптимизации: возвращенная запись всегда будет храниться в фактической ячейке памяти, тогда как истинная локальная переменная может быть связана с регистром ЦП. Компилятор также не позволит вам использовать такие переменные для операторов "for", и это большая проблема.

3 голосов
/ 29 июня 2011

В Delphi нет способа ограничить область действия переменной до целой подпрограммы. И в случае единственной целочисленной переменной не имеет смысла беспокоиться об этом ... Но в случае большой структуры данных вы должны распределять ее динамически, а не статически, т.е. вместо

var integers: array[1..10000]of Integer;

использование

type TIntArray: array of Integer;
var integers: TIntArray;
If acondition then
 begin
    SetLength(integers, 10000);
    ...
 end;
2 голосов
/ 29 июня 2011

Прокомментировав все это - есть трюк для вечеринки, который есть у Delphi, который имеет гораздо больше применений, чем простая локальная переменная, и может достичь вашей цели:

  function Something: Integer;
  begin 
    // don't want any too long local variables...
    If acondition then
      asm
        // now I have lots of 'local' variables available in the registers 
        mov EAX, @AnotherVariable  //you can use pascal local variables too!
        // do something with the number 3
        Add EAX, 3
        mov @Result, EAX
        jmp @next
 @AnotherVariable: dd 10
 @next:
      end;
    end;
  end; 

:)) немного бессмысленного примера...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...