2010-08-27 3 views
1

Я только что прочитал этот вопрос: Why are different case condition bodies not in different scope?Скобки, определяющие скобки и стек?

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

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

ответ

3

Все, что он делает, это определение другой области действия, оно не переводится в вызов метода. Помните, что для местных жителей 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

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

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

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

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

+0

вы имеете typo'd 'variables' в ваших последних два предложений - я не исправил его упаковывает вы добавляете в свой ответ на данный момент и наши правки перекрываются =) (Плюс я думаю, что это плохой этикет, чтобы отредактировать кого-то, пока вы не уверены, что они закончили с ним!) (* Изменить: удалить опечатку из слова предложение * ** sigh **) – Rob

+2

Итак, у меня был 25% -ный показатель успеха в написании этого слова (на самом деле я, вероятно, тоже ошибся в четвертый раз, но я сам это поймал ...) –

+0

Лучше не упоминать о том, что вы плюрализовались 'переменная' в вашем предпоследнем предложении, тогда ... ;-) О, и +1 от меня за ваш ответ =) – Rob

1

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

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

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; 
     } 
    } 
} 

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

Блоки всегда имеют доступ к их внешних областей или это не будет работать:

void foo() { 
    int a = 123; 
    if (true) { 
     a = 345; // accessing a in outer scope 
    } 
} 
+0

Ах, во второй части вашего ответ, один о переменных, объявленных перед областью. Я должен был подумать об этом, но я был занят, думая об этом, придумывая метод. Я действительно слишком усложнил этот вопрос, когда думал об этом. –

0

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

Кроме того, могут возникнуть проблемы при использовании 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 
Смежные вопросы