内核编码风格和 gnome 的 C 风格指南都指出:
Do not unnecessarily use braces where a single statement will do.
if (condition)
action();
Run Code Online (Sandbox Code Playgroud)
但同时它有时应该被使用,如在以下else分支中:
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
Run Code Online (Sandbox Code Playgroud)
是否有任何技术或可用性原因更喜欢这种方式?有什么客观的理由不每次都把牙套放在那里吗?
只有风格和易于编辑相关的原因。
无论是否省略大括号,C 编译器都必须像大括号在那里一样(+ 一对围绕整个迭代语句(if或if- else))。
选择语句是一个块,其范围是其封闭块范围的严格子集。每个关联的子语句也是一个块,其范围是选择语句范围的严格子集。
这些隐式块的存在可以用枚举很好地证明:
#include <stdio.h>
int main()
{
enum{ e=0};
printf("%d\n", (int)e);
if(1) printf("%d\n", (sizeof(enum{e=1}),(int)e));
if(sizeof(enum{e=2})) printf("%d\n", (int)e);
printf("%d\n", (int)e);
//prints 0 1 2 0
}
Run Code Online (Sandbox Code Playgroud)
迭代语句也存在类似的规则:6.8.5p5。
这些隐式块还意味着在迭代或选择语句中定义的复合文字仅限于这种隐式块。这就是为什么标准中的示例http://port70.net/~nsz/c/c11/n1570.html#6.5.2.5p15将复合文字放在显式标签之间,goto而不是简单地使用while语句,这会限制文字的范围,无论是否使用显式大括号。
虽然它可能很诱人,但永远不要这样做:
if (Ptr) Ptr = &(type){0}; //WRONG way to provide a default for Ptr
Run Code Online (Sandbox Code Playgroud)
gcc -O3由于范围规则,上述导致 UB(实际上是非工作智慧)。
执行上述操作的正确方法是:
type default_val = {0};
if (Ptr) Ptr = &default_val; //OK
Run Code Online (Sandbox Code Playgroud)
或与:
Ptr = Ptr ? Ptr : &(type){0}; //OK
Run Code Online (Sandbox Code Playgroud)
这些隐式块在 C99 中是新的,并且内部块(用于选择语句 (=ifs))被很好地合理化(C99RationaleV5.10.pdf,第 6.8 节)作为重构的辅助工具,防止从先前未加括号的分支中添加的大括号改变含义.
不幸的是,围绕整个选择语句的最外层分支似乎没有很好地合理化(更准确地说,它根本没有合理化)。它似乎是从迭代语句的规则复制而来的,它似乎复制了 C++ 规则,其中for-loop-local 变量在整个 for 循环的最后被破坏(就像 for 循环被加括号一样)。
(不幸的是,我认为对于选择语句,最外层的隐式 {} 弊大于利,因为它阻止您拥有仅在调用方范围内进行堆栈分配但还需要检查的宏,因为那样您只能检查这样的带有?:但不带有 的宏if,这很奇怪。)