【问题标题】:Why enclose blocks of C code in curly braces?为什么将 C 代码块用花括号括起来?
【发布时间】:2010-12-13 06:17:56
【问题描述】:

我正在查看一些 C 代码,并注意到它充满了围绕代码块的大括号,没有任何类型的控制结构。看一看:

//do some stuff . . .
fprintf(stderr, "%.2f sec\n", (float)(clock() - t) / CLOCKS_PER_SEC);
{
    //a block! why not?
    char *tmp_argv[3];
    tmp_argv[0] = argv[0]; tmp_argv[1] = str; tmp_argv[2] = prefix;
    t = clock();
    fprintf(stderr, "[bwa_index] Convert nucleotide PAC to color PAC... ");
    bwa_pac2cspac(3, tmp_argv);
    fprintf(stderr, "%.2f sec\n", (float)(clock() - t) / CLOCKS_PER_SEC);
}

为什么要在代码中插入这样的块?它充满了他们。有某种性能优势吗?一些神秘的C东西?为什么???

编辑:此代码来自BWA,这是一个使用Burrows-Wheeler transform 将小序列与大参考序列对齐的生物信息学程序,以防你们中的任何人想知道。此代码示例与应用程序的功能并不是特别相关。

【问题讨论】:

  • 这种做法在 C 和 C++ 中可能有不同的动机。您的代码看起来像 C,而您的问题被标记为 C++。你确定你正确地标记了你的问题吗?
  • 啊,不错。这确实是 C。我不知道为什么我认为它是 C++。更改了标签。
  • 然后也编辑文本。它仍然说“我正在查看一些 C++ 代码......”

标签: c scope curly-braces


【解决方案1】:

需要遗留代码 { } 才能进行声明

在 C89 中,您不能只在任何地方执行 int i;;声明仅在块的开头有效。

所以:

a = 1;
int i; /* error */
i = 2;

...无效,但是

a = 1
if (e) {
  int i;

...很好,就像一个普通的块一样。

即使在声明变得有效 (C99) block-item(s) 之后,所产生的样式仍然继续存在,部分原因是惯性,部分原因是为了向后可移植性,还因为建立新的范围是有意义的声明。

【讨论】:

  • 严格来说,声明在 C 中从未变成 语句。即使在 C99 中,声明也不是 not 语句。在 C++ 中它们是,但在 C 中不是。
  • 基于这个答案,它可能表明不再需要普通的块成语。事实上,许多人喜欢继续使用它来限制他们创建的变量的范围,即使不再需要在块中间声明新变量。我认为范围界定答案比传统答案更重要,尽管 C89 兼容性也是这样做的一个很好的理由(因为很少有编译器能很好地实现 C99)。
  • @AndreyT:叹息,你是对的,当时这么说确实让我有点困扰。作为记录:-) C89:复合语句 ::= { 声明列表(选择)语句列表(选择)},而在 C99 中:块项目 ::= 声明 |声明。
  • 如果您在家庭逆向计算实验室或虚拟机中回溯到足够远的地方,您只会得到功能块的开头,而不是内部块。
【解决方案2】:

范围变量。例如。变量tmp_argv 仅在大括号之间有效。

【讨论】:

  • 虽然这里似乎不是这种情况,但作用域的结束会触发析构函数,这些析构函数直到以后才会被触发。
  • @Keith: +1 我过去常常在我的多线程代码中做这种事情,创建类会在其 ctor 中锁定互斥锁并在 dtor 中解锁它
【解决方案3】:

我最近发现的另一个用例是当你有打开/关闭语义并且你想清楚地标记“内部”代码时:

f = fopen('file');
{
    // do stuff
}
fclose(f);

这可以很好地提醒您关闭/释放对象,并使代码更加简洁。

【讨论】:

    【解决方案4】:

    块是一个范围,它决定了变量的生命周期,以及它们对编译器的可见性。因此,当控制退出块时,在块内创建的变量就会消失。

    当这些变量是具有构造函数和析构函数的类的实例时,它会非常方便。

    但是,在您的示例中并没有太大优势。

    【讨论】:

      【解决方案5】:

      它正在创建一个范围。堆栈对象在超出范围时被销毁。看起来它正在做某种类型的打字,这意味着每个块都是他们想要计时的东西。但是,我没有看到任何作用域计时器对象,所以,是的,没有任何意义。

      【讨论】:

        【解决方案6】:

        您在块内声明的变量是该块的本地变量。这样您就可以在代码的其他位置(如下)重新定义tmp_argv,而不会与这段代码冲突。

        【讨论】:

          【解决方案7】:

          就这些了吗?也许程序员在代码的其他地方使用了tmp_argv。我想不出任何其他原因,因为{} 之间的tmp_argv 与大括号之外的任何内容都是分开的。

          【讨论】:

          • 不,还有很多。我只是随便举了一个例子。
          • 那么程序员在大括号外的范围内使用tmp_argv吗?
          【解决方案8】:

          我有时会在这些情况下使用块: - 本地化变量 - 或者更容易阅读 ...

          【讨论】:

            【解决方案9】:

            嗯 - 我可能不在此处列出,但我认为在此类块内定义的局部变量在块外将无效

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-04-07
              • 2011-04-07
              • 1970-01-01
              • 2012-01-18
              • 2021-09-21
              相关资源
              最近更新 更多