本地作用域和函数作用域的区别

7

曾经我认为这两个词意思相同,但是在阅读更多相关内容后,我仍然不清楚它们之间的区别。难道本地作用域有时不是指函数作用域吗?而且什么意思是只有标签具有函数作用域?


10
在C++03中有时被称为“局部作用域”,有时被称为“块作用域”的东西,现在在C++11中被统一称为“块作用域”。少了一个困惑的来源! - Johannes Schaub - litb
5个回答

17
void doSomething()
{                                    <-------
     {                   <----               | 
                              |              |
         int a;           Local Scope    Function Scope
                              |              |
     }                   <----               | 
}                                    <------- 

函数作用域在外层的 {} 之间。

局部作用域在内层的 {} 之间。

请注意,任何由 {} 创建的作用域都可以被称为局部作用域,而函数体开头的 {} 则创建了函数作用域。因此,有时局部作用域和函数作用域可能相同。

什么意思,只有标签具有函数作用域?

标签 只是紧跟着冒号的标识符。 标记语句用作 goto 语句的目标。 标签可以在它们出现的函数中的任何地方使用,但不能在函数体外引用。 因此,它们被认为具有函数作用域。

代码示例:

int doSomething(int x, int y, int z)
{
     label:  x += (y + z);   /*  label has function scope*/
     if (x > 1) 
         goto label;
}

int doSomethingMore(int a, int b, int c)
{
     if (a > 1) 
         goto label; /*  illegal jump to undefined label */
}

5

本地作用域是指在一个 { 和它的闭合 } 之间的区域。函数作用域是指在函数开头的 { 和结束的 } 之间的区域,其中可能包含更多的“本地”作用域。标签在定义它的整个函数中都是可见的,例如:

int f( int a ) 
{
    int b = 8;
    if ( a > 14 )
    {
       int c = 50;
       label:
       return c - a - b;
    }
    if ( a > 7 ) goto label;
    return -99;
}

int c在其封闭块之外不可见。标签在其封闭块之外可见,但仅限于函数范围。


3
我一直认为标签具有全局作用域,但函数作用域更合理。 - deft_code
如果标签具有全局作用域,你可以从一个函数的主体跳转到另一个函数的主体,这将是疯狂的。 - Rob K
不,@Rob,如果语言也允许非局部goto,则只能从一个函数跳转到另一个函数。它们不一定是一个套餐,但仅限于具有全局标签名称的本地goto意味着在选择标签名称时必须小心,以避免干扰程序中其他位置的标签,就像选择预处理器宏名称时一样。 - Rob Kennedy
很好的澄清。全局范围的标签名称如果没有相应的非本地跳转,就毫无意义。正如你所说,那只会污染命名空间。 - Rob K

2
有时候本地范围指的是函数的范围吗?
是的。在大多数C语言中,变量在它们被声明的范围内有效。如果你在一个函数内声明一个变量,但没有在任何其他代码块中声明它,那么这个变量通常被称为“本地”或“自动”变量。你可以在函数的任何地方引用它。另一方面,如果你在另一个代码块内声明变量 - 比如,在条件语句的主体中,则该变量仅在该块内有效。这里有几个其他答案给出了很好的例子。
什么意思只有标签有函数作用域?
上下文会很有帮助,但它意味着你不能从一个函数跳转到不同函数中的标签。
void foo(int a) {
    if (a == 0) goto here;  // okay -- 'here' is inside this function
    printf("a is not zero\n");
    goto there;             // not okay -- 'there' is not inside this function
here:
    return;
}

void bar(int b) {
    if (b == 0) goto there; // okay -- 'there' is in this function
    printf("b is not zero\n");
there:
    return;
}

不想引起争议,但标签的使用范围可能不会经常出现。标签主要在使用goto语句时非常有用,但这种情况很少发生,即使您选择使用goto,您也可能不会尝试跳转到另一个函数。


具有讽刺意味的是,据我所知,C语言没有局部作用域,只有函数作用域。 - Mooing Duck

1
函数的作用域略大于函数体的作用域:函数参数在外部作用域,而本地变量仅在内部作用域中。这在函数尝试块中最明显地体现出来:
void f(int a) try {
  // function body
} catch(...) {
  // catch block
}

在 catch 块内,只有函数作用域中的变量仍然在作用域内,而不是局部变量。
当然,您也可以并且经常引入更深层嵌套的作用域,例如在 for 循环体或条件体中。

+1 我过去写了很多C++,但我从未见过那种结构。 - Caleb
@Caleb:你可能想看一下这个 - Alok Save
@Caleb:想象一下将其用于构造函数...然后立即忘记使用this :-) - Kerrek SB
@KerrekSB:这让我想知道我还错过了什么,但我不确定我真的想知道。 - Caleb

1
bool m[3][3];
void f1()
{
  int i;
  // redefining a variable with the same name in the same scope isn't possible
  //int i; //error C2086: 'int i' : redefinition
}

void f2()
{
  int i; // ok, same name as the i in f1(), different function scope.

  {
    int i; // ok, same name as the i above, but different local scope.
  }

  // the scope if the following i is local to the for loop, so it's ok, too.
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      if (m[i][j])
        goto loopExit;
    }
  }
loopExit:
  std::cout << "done checking m";
// redefining a label with the same name in the same function isn't possible
// loopExit:; // error C2045: 'loopExit' : label redefined
}

void f3()
{
loopExit:; // ok, same label name as in f2(), but different function scope
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接