Область определения скобок и стека? - PullRequest
1 голос
/ 27 августа 2010

Я только что прочитал этот вопрос: Почему разные тела условий дел не находятся в разных областях?

Это вопрос Java, но мой вопрос относится как к C #, так и к Java (и к любому другому языку с этой функцией уменьшения объема).

В этом вопросе OP говорит о том, как он знает, что он может вручную добавить {}, чтобы уточнить область действия каждого случая в коммутаторе. У меня вопрос, как это работает? Это идет вверх по стеку, как если бы это был вызов метода? Если да, что он делает для того, чтобы он все еще имел доступ к другим переменным, объявленным до этой области?

Ответы [ 4 ]

3 голосов
/ 27 августа 2010

Все, что он делает, это определяет другую область, она не переводится в вызов метода. Помните, что для локальных пользователей CLR / JVM может решить вообще не использовать для них пространство стека, а может использовать регистры процессора. В некоторых случаях, если вы извините за каламбур, он может решить оптимизировать некоторые из местных жителей, поскольку они не нужны. Он может даже решить, что может использовать один регистр или область памяти «в стеке» для нескольких переменных, поскольку они никогда не будут перекрываться.

Пример из связанного вопроса:

switch(condition) {
  case CONDITION_ONE: {
    int account = 27373;
  }
  case CONDITION_TWO: {
    // account var not needed here
  }
  case CONDITION_THREE: {
    // account var not needed here
  }
  case CONDITION_FOUR: {
    int account = 90384;
  }
}

В нынешнем виде этот код функционально идентичен:

int account;

switch(condition) {
  case CONDITION_ONE: {
    account = 27373;
  }
  case CONDITION_TWO: {
    // account var not needed here
  }
  case CONDITION_THREE: {
    // account var not needed here
  }
  case CONDITION_FOUR: {
    account = 90384;
  }
}

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

2 голосов
/ 27 августа 2010

Область действия определяется компилятором во время компиляции.Это мало влияет на фактическое расположение переменных в памяти.Следовательно, если бы я написал:

func()
{ 
    int a;
    {
      int b;
    }
    {
      int c;
    }
}

Компилятор может выбрать создание трех переменных и выделить место для всех трех в начале функции, или он может просто выделить пространство для двух переменных и использоватьто же самое пространство для b & c.

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

1 голос
/ 27 августа 2010

У меня вопрос, как это работает?Идет ли он вверх по стеку, как если бы это был вызов метода?

Он работает так же, как любая другая пара {}, используемая для создания новой локальной области.Нет разницы в объеме между этим:

void foo() {
    {
        int a = 123;
    }
    // a is gone here
    {
        // different a
        float a = 12.3f;
    }
}

и этим:

void foo() {
    switch (123) {
    case 1:
        {
            int a = 123;
        }
        // a is gone here
        break;

    case 2:
        {
            // different a
            float a = 12.3f;
        }
    }
}

Если так, что он делает, чтобы он все еще имел доступ к другим переменным, объявленным доscope?

Блоки всегда имеют доступ к своим внешним областям, иначе это не сработает:

void foo() {
    int a = 123;
    if (true) {
        a = 345; // accessing a in outer scope
    }
}
0 голосов
/ 27 августа 2010

Любые переменные, объявленные внутри области видимости, могут быть доступны только внутри этой области и всех областей видимости внутри нее.Таким образом, в функции можно использовать {} во многих языках программирования для создания переменных, которые будут разрушены при выходе из этой области.

Кроме того, могут возникнуть проблемы при использовании switch и при отсутствии областей, как показаноэтим небольшим фрагментом кода C:

int main() {
  int foo = 4;
  int bar = getbar(); // getbar() is a function returning an integer
  switch(bar)
  {
    case 1:
      int abc = 6;
      break;
    case 2:
      int abc = 7; // compiler error: 'abc' was defined twice in this scope
      break;
  }
}
int abc = 147; // This is no error, as 'abc' fell out of scope when
// leaving the `switch` statement

Как видите, abc был объявлен дважды в области действия switch, что приводит к ошибке.Это легко было бы исправить, указав каждому case свою собственную переменную область видимости:

int main() {
  int foo = 4;
  int bar = getbar(); // getbar() is a function returning an integer
  switch(bar)
  {
    case 1:
    {
      int abc = 6;
      break;
    }
    case 2:
    {
      int abc = 7; // no more errors, since these declarations will destruct when
      // falling out of scope
      break;
    }
  }
}
int abc = 147; // This is no error, as 'abc' fell out of scope when
// leaving the `switch` statement
...