您无需混合声明和代码来限制作用域。您可以这样做:
{
int c;
c = 1;
{
int d = c + 1;
}
}
虽然这是一个老问题,但我认为惯性是这些项目仍然使用 ANSI C 声明规则的原因。
不过还有其他一些可能性,从合理到荒谬:
可移植性。许多开源项目基于 ANSI C 的严谨规则来编写软件是最具可移植性的做法。
历史。许多这样的项目在 C99 规范之前就存在了,作者可能更喜欢一致的编码风格。
无知。提交代码的程序员比 C99 更早,不知道混合声明和代码的好处。(或者:开发者完全意识到可能出现的权衡,并决定混合声明和语句不值得努力。我非常不同意,但很少有两个程序员会对任何东西达成一致的见解。)
FUD(恐惧、不确定性和怀疑)。程序员认为混合声明和代码是“C++主义”,因此不喜欢它。
没有理由为了没有性能提升的表面变化而重写Linux内核。
如果代码基础已经运作正常,为何要因为表面原因而做出改变呢?
我不记得内核代码风格指南中有任何禁止这样做的规定。然而,它确实说函数应该尽可能小,并且只做一件事情。这就解释了为什么声明和代码混合在一起是罕见的。
在一个小函数中,在作用域开始时声明变量就像一种引子,告诉你接下来会发生什么。在这种情况下,变量声明的移动是如此有限,以至于它可能没有任何影响,或者通过将吆喝者推到人群中来隐藏一些关于功能的信息。有一个原因,为什么国王进入房间之前要先宣布他的到来。
另一方面,必须混合变量和代码才能使其可读的函数可能太大了。这是一个迹象(连同太多嵌套块、内联注释和其他东西),表明函数的某些部分需要抽象成单独的函数(并声明为static
,以便优化器可以将它们内联)。
将声明放在函数开头的另一个原因是:如果您需要重新排序代码中语句的执行顺序,您可能会移动变量的作用域而没有意识到,因为在代码中间声明变量的作用域不明显(除非您使用块来显示作用域)。这很容易修复,所以只是一种烦恼,但新代码经常经历这种转换,烦恼可能会累积。
还有一个原因:您可能会想要声明一个变量来接收函数的错误返回代码,如下所示:
void_func();
int ret = func_may_fail();
if (ret) { handle_fail(ret) }
这是一个非常合理的做法。但是:
void_func();
int ret = func_may_fail();
if (ret) { handle_fail(ret) }
....
int ret = another_func_may_fail();
if (ret) { handle_other_fail(ret); }
糟糕!ret
被定义了两次。你说:“那又怎样?删除第二个声明。”但这会使代码不对称,最终导致更多的重构限制。
当然,我自己也会混合声明和代码;没有理由要死守某种规则(否则你的业力可能会压垮你的教条:-)。但你应该知道相关的问题。
这样做没有好处。在函数开头声明所有变量(类似Pascal)更加清晰,在C89中,您也可以在每个作用域的开头声明变量(例如循环内部),这既实用又简洁。
也许这并不是必需的,也许分离是好的?我用C++实现,它也有这个功能。
没有理由改变像这样的代码,而且C99仍然没有得到广泛支持。这主要是关于可移植性的问题。
gcc -std=c89 -pedantic
进行实际实验几个小时后,你就会发现这一点。为什么不先尝试一下呢?基于你明显不理解的东西来评价代码可读性是不明智的。 - user3137850