为什么我们要将一段代码放在大括号内?

Why would we put a block of code inside braces?

我遇到了这段我无法向自己解释的 C 代码:

 check_eeprom_data();
 {

     unsigned char serial_num[5];
     printStr("\nSerNUM:");
     eeprom_read(confEE_SERIAL_NUM, serial_num, 5);
     printBuffAsHex(serial_num, 5);

 }

为什么需要这些花括号来括起这部分代码?如果没有括号,它有什么不同?

在 C99 之前,变量总是需要在块的开头定义(在任何语句之前)。所以如果你想定义一个靠近它被使用的地方的变量(如果它只有很短的生命周期)那么引入一个块是有意义的(即用大括号括起一段代码),按照你的例子问题。

请注意,许多 C 编译器(尤其是嵌入式编译器和臭名昭著的 Microsoft Visual C 编译器)支持 C99 的速度非常慢,因此即使在今天,这种 C89 编码风格也并不少见。

那个代码块可能是为了限制 serial_num 的存在而存在的。当您用大括号括起某些代码时,您正在创建一个新的范围块。

因为在 C89(和 K&R C)中,声明必须位于 的开头。注意开{unsigned char serial_num[5];的声明。最好使变量的范围尽可能小,并在使用它们的最内层块中声明它们。

在 C99 中,声明可以与代码混合,就像在 C++ 中一样。

他们引入了一个新的范围来限制 serial_num 的生命周期(以及内部做出的任何其他声明)。这样,右大括号之后的代码就不会被这些变量污染。

在 C99 和 C11 中,可以在语句块中的任何位置引入新的局部变量,因此代码段中的大括号不是必需的。

但是,在 C89 中,新局部(块作用域)变量的声明只能出现在块的开头。因此,您示例中编写的代码段可以使用 C89 编译器进行编译。

在花括号内声明的局部变量只存在于那里(并且只在那里可见)。所以当代码离开花括号块时 serial_num 将被销毁

这用于限制变量的范围。

在你的情况下,

check_eeprom_data();
 {

  unsigned char serial_num[5];
  printStr("\nSerNUM:");
  eeprom_read(confEE_SERIAL_NUM, serial_num, 5);
  printBuffAsHex(serial_num, 5);
 }

您不能在 范围 之外使用 serial_num

此外,在 C99 之前,必须在块的开头进行变量声明。因此,要在特定范围内定义和使用变量,就要使用这种风格/方法/技术。

让我们将其与一个简单的程序进行比较,以便更好地理解。

#include <stdio.h>

int main(void) {

    {                           //scope starts
        int p = 5;
            printf("%d", p);    //p is known here
    }                           //scope ends

    printf("%d", p);  // wait, what is p????

    return 0;
}

编译结果见一个LIVE EXAMPLE

大括号是为了方便并行代码结构。也就是说,假设您想再次执行相同的操作。如果没有大括号,您将无法剪切和粘贴该代码块,也许需要修改。这是因为您只能在任何范围的顶部声明一次 serial_num 。所以它会像这样出来:

unsigned char serial_num[5];
printStr("\nSerNUM:");
eeprom_read(confEE_SERIAL_NUM, serial_num, 5);
printBuffAsHex(serial_num, 5);

printStr("\nSerNUM:");
eeprom_read(confEE_SERIAL_NUM, serial_num, 5);
printBuffAsHex(serial_num, 5);

注意到我无法再次声明 serial_num 了吗?所以我什至不能保持块不变我必须删除该行。如果我想在我需要将声明上移之前引入类似的块。如果我想改变 serial_num 的长度,我会被卡住,因为你只能声明一次 serial_num范围。

有了大括号,我就有了一个平行的视觉结构(适合剪切和粘贴,有或没有修改),我也可以灵活地用不同的方式声明 serial_num每个范围的长度。

{
  unsigned char serial_num[5];
  printStr("\nSerNUM:");
  eeprom_read(confEE_SERIAL_NUM, serial_num, 5);
  printBuffAsHex(serial_num, 5);
}

{
  unsigned char serial_num[8];
  printStr("\nSerNUM:");
  eeprom_read(confEE_SERIAL_NUM, serial_num, 8);
  printBuffAsHex(serial_num, 8);
}

注意到单独的作用域如何允许一个人独立处理每个块而不会相互干扰吗?所以我可以重新排序块,即使它们使用相同的符号名称 serial_num 而不必担心更改 serial_num[=31 的声明=].事实上,我可以在本地为每个块声明 serial_num,无论符号名称是否与其他块匹配。

这种通用模式用于增加不同本地代码块之间的隔离,这些代码块不应相互干扰,声明从一个块泄漏到下一个块。它可以保护您免受符号名称冲突的影响,并在您希望每个块尽管与周围的其他块相似但仍保留本地风味时防止意外重用符号。