为什么用花括号括起C代码块?

jer*_*son 61 c scope curly-braces

我正在看一些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);
}
Run Code Online (Sandbox Code Playgroud)

为什么要在代码中插入这样的块?它充满了它们.是否有某种性能优势?一些神秘的C事?为什么???

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

Dig*_*oss 91

传统代码需要{}才能完成声明

在C89,你不能随便做int i;任何事情; 声明仅在块的开头有效.

所以:

a = 1;
int i; /* error */
i = 2;
Run Code Online (Sandbox Code Playgroud)

......无效,但是

a = 1
if (e) {
  int i;
Run Code Online (Sandbox Code Playgroud)

......很好,就像平原一样.

即使在声明变为有效(C99)块项目之后,结果样式仍然继续,部分是惯性,部分是为了向后可移植性,并且还因为建立新声明的范围是有意义的.

  • @AraK - 我不同意.根据这个答案,可能不再需要普通的块成语.事实上,许多人喜欢继续使用它来限制他们创建的变量的范围,即使不再需要这样做以在块的中间声明新变量.我认为范围界定答案比传统答案更重要,尽管C89兼容性也是这样做的一个很好的理由(因为很少有编译器能很好地实现C99). (11认同)
  • 严格来说,声明永远不会成为C中的*语句*即使在C99声明中也不是*语句.在C++中它们是,但不是在C. (2认同)

jld*_*ont 38

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

  • 虽然这里似乎不是这种情况,但是范围的结束会触发析构函数,否则直到后来才会触发这些析构函数. (9认同)
  • @Keith:+1我过去常常在我的多线程代码中做这种事情,创建可以锁定互斥锁中的互斥锁并在dtor中解锁它的类 (2认同)

Mik*_*ler 8

我最近发现的另一个用例就是当你有开/关语义而你想清楚地标记'内部'代码时:

f = fopen('file');
{
    // do stuff
}
fclose(f);
Run Code Online (Sandbox Code Playgroud)

这很好地提醒你关闭/释放对象,并使代码更清洁.


Pau*_*nde 7

块是确定变量生命周期的范围,以及它们对编译器的可见性.因此,当控件退出块时,在块中创建的变量会消失.

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

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


i_a*_*orf 6

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


pgb*_*pgb 5

您在块中声明的变量是该块的本地变量.通过这种方式,您可以tmp_argv在代码的其他位置(下方)重新定义,而不会与此代码冲突.