C风格语言中匿名{}块的目的是什么?

时间:2009-02-01 01:48:27

标签: c# c++ c

C风格语言(C,C ++,C#)中匿名{}块的用途是什么

示例 -



void function()
{

  {
    int i = 0;
    i = i + 1;
  }

  {
    int k = 0;
    k = k + 1;
  }

}

修改 - 感谢所有优秀的答案!

17 个答案:

答案 0 :(得分:66)

它将变量的范围限制在{}。

中的块

答案 1 :(得分:20)

括号指定范围区域 - 括号内声明的任何内容都是不可见的。

此外,在C ++中,在堆栈上分配的对象(例如,不使用'new')将在超出范围时被破坏。

在某些情况下,它也可以是突出显示作者认为值得关注的人看到源的特定功能的一种方式。这是否是一个好的用途是有争议的,但我已经看到它完成。

答案 2 :(得分:13)

它们通常用于RAII目的,这意味着当对象超出范围时将释放给定资源。例如:

void function()
{
    {
        std::ofstream out( "file.txt" );
        out << "some data\n";
    }
    // You can be sure that "out" is closed here
}

答案 3 :(得分:7)

另一个常见用途是使用OpenGL的glPushMatrix()glPopMatrix()函数来创建与矩阵堆栈相关的逻辑块:

glPushMatrix();
{
    glTranslate(...);
    glPushMatrix();
    {
        glRotate(...);
        // draw some stuff
    }
    glPopMatrix();
    // maybe draw some more stuff
}
glPopMatrix();

答案 4 :(得分:6)

  

{ ... }打开了一个新范围

在C ++中,您可以像这样使用它们:

void function() {
    // ...
    {
        // lock some mutex.
        mutex_locker lock(m_mutex);
        // ...
    }
    // ...
}

一旦控件退出块,互斥锁将被破坏。在它的析构函数中,它会自动解锁它所连接的互斥锁。这经常被完成,称为RAII(资源获取是初始化)以及SBRM(范围绑定资源管理)。另一个常见的应用是分配内存,然后在析构函数中再次释放该内存。

另一个目的是做几件类似的事情:

void function() {
    // set up timer A
    {
        int config = get_config(TIMER_A);
        // ... 
    } 

    // set up timer B
    {
        int config = get_config(TIMER_B);
        // ...
    } 
}

它会将事物分开,这样就可以轻松找到不同的构建块。您可以使用具有相同名称的变量,例如上面的代码,因为它们在其范围之外不可见,因此它们不会相互冲突。

答案 5 :(得分:6)

class ExpensiveObject {
public:
    ExpensiveObject() {
        // acquire a resource
    }
    ~ExpensiveObject() {
        // release the resource
    }
}

int main() {
    // some initial processing
    {
        ExpensiveObject obj;
        // do some expensive stuff with the obj
    } // don't worry, the variable's scope ended, so the destructor was called, and the resources were released
    // some final processing
}

答案 6 :(得分:5)

通过创建新范围,可以使用它们在switch语句中定义局部变量。

e.g。

switch (i)
{
    case 0 :
        int j = 0;   // error!
        break;

VS

switch (i)
{
    case 0 :
    {
        int j = 0;   // ok!
    }
    break;

答案 7 :(得分:4)

它们经常用于作用域变量,因此变量是由大括号定义的任意块的局部变量。在你的例子中,变量i和k在它们的括号之外是不可访问的,因此不能以任何偷偷摸摸的方式修改它们,并且这些变量名可以在代码的其他地方重用。使用大括号创建这样的本地范围的另一个好处是,在具有垃圾收集的语言中,垃圾收集器知道清除超出范围的变量是安全的。这在C / C ++中不可用,但我相信它应该在C#中。

考虑它的一个简单方法是大括号定义一段原子代码,类似于命名空间,函数或方法,但无需实际创建命名空间,函数或方法。

答案 8 :(得分:4)

你正在做两件事。

  1. 您正在强制对该块中的变量进行范围限制。
  2. 您正在启用兄弟代码块以使用相同的变量名称。

答案 9 :(得分:3)

据我了解,它们只是用于范围界定。它们允许您在父/兄弟范围中重用变量名称,这可能会不时有用。

编辑:这个问题实际上已在another Stack Overflow question得到解答。希望有所帮助。

答案 10 :(得分:3)

当然确定范围。 (那匹马被打死了吗?)

但是如果你看一下语言定义,就会看到如下模式:

  • 如果 表达 声明
  • 如果 表达 声明 其他 声明
  • 切换 表达 声明
  • while 表达 声明
  • 执行 声明 ,而 表达 ;

它简化了语言语法, compound-statement 只是几个可能的语句之一。


复合声明 { 声明列表选择 }

语句列表

  • 语句
  • 陈述列表 陈述

语句

  • 标记的语句
  • 表达式语句
  • 化合物语句
  • 选择语句
  • 迭代语句
  • 跳语句
  • 声明陈述
  • 尝试块

答案 11 :(得分:3)

正如前面提到的海报所述,它限制了变量在声明范围内的使用。

在垃圾收集语言(如C#和Java)中,它还允许垃圾收集器回收范围内使用的任何变量所使用的内存(尽管将变量设置为null会产生相同的效果)。

{
    int[] myArray = new int[1000];
    ... // Do some work
}
// The garbage collector can now reclaim the memory used by myArray

答案 12 :(得分:2)

如果您仅限于ANSI C,那么它们可用于将变量声明为更接近您使用它们的位置:

int main() {
    /* Blah blah blah. */
    {
        int i;
        for (i = 0; i < 10; ++i) {
        }
    }
}

不需要现代的C编译器。

答案 13 :(得分:2)

关于范围,它指的是程序的一个部分中的变量和方法对该程序的另一部分的可见性,请考虑此示例:

int a=25;
int b=30;
{ //at this point, a=25, b=30
     a*=2; //a=50, b=30
     b /= 2; //a=50,b=15
     int a = b*b; //a=225,b=15  <--- this new a it's
                  //                 declared on the inner scope
}
//a = 50, b = 15

答案 14 :(得分:1)

一个有用的use-cas ihmo 在C ++中定义关键部分。 e.g:

int MyClass::foo()
{    
   // stuff uncritical for multithreading
   ...
   {
      someKindOfScopeLock lock(&mutexForThisCriticalResource);
      // stuff critical for multithreading!
   }
   // stuff uncritical for multithreading
   ...    
}

使用匿名作用域不需要显式调用互斥锁或信号量的锁定/解锁。

答案 15 :(得分:1)

要提到的一件事是范围是编译器控制的现象。即使变量超出范围(编译器将调用任何析构函数; POD类型立即优化到代码中),它们仍保留在堆栈中,并且父范围中定义的任何新变量都不会在gcc或clang上覆盖它们(即使使用-Ofast进行编译)。通过地址访问它们是不确定的行为,因为变量在概念上超出了编译器级别的范围-编译器将阻止您通过它们的标识符访问它们。

#include <stdio.h>
int main(void) {
  int* c;
  {
    int b = 5; 
    c=&b;
  }
  printf("%d", *c); //undefined behaviour but prints 5 for reasons stated above
  printf("%d", b); //compiler error, out of scope
  return 0;
}

另外,对于,如果,否则,所有都在匿名块之前。复合语句,根据条件执行一个块或另一个块。

答案 16 :(得分:0)

我将它用于需要临时变量的代码块。