为什么在Linux 内核或GNOME等开源 C 项目中仍然没有使用C99 混合声明和代码?
我真的很喜欢混合声明和代码,因为它使代码更具可读性,并通过将变量的范围限制在尽可能窄的范围内来防止难以看到的错误。这是 Google为 C++推荐的。
例如,Linux至少需要GCC 3.2,而 GCC 3.1支持C99 混合声明和代码
为什么在Linux 内核或GNOME等开源 C 项目中仍然没有使用C99 混合声明和代码?
我真的很喜欢混合声明和代码,因为它使代码更具可读性,并通过将变量的范围限制在尽可能窄的范围内来防止难以看到的错误。这是 Google为 C++推荐的。
例如,Linux至少需要GCC 3.2,而 GCC 3.1支持C99 混合声明和代码
您不需要混合声明和代码来限制范围。你可以做:
{
int c;
c = 1;
{
int d = c + 1;
}
}
在 C89 中。至于为什么这些项目没有使用混合声明(假设这是真的),很可能是“如果它没有坏就不要修复它”的情况。
这是一个老问题,但我会建议惯性是大多数这些项目仍然使用 ANSI C 声明规则的原因。
然而,还有许多其他的可能性,从有效到荒谬:
可移植性。许多开源项目的工作假设是迂腐的 ANSI C 是编写软件的最便携的方式。
年龄。其中许多项目早于 C99 规范,作者可能更喜欢一致的编码风格。
无知。提交早于 C99 的程序员并没有意识到混合声明和代码的好处。(另一种解释:开发人员完全意识到潜在的权衡,并认为混合声明和语句不值得努力。我非常不同意,但很少有两个程序员会就任何事情达成一致。)
FUD。程序员将混合声明和代码视为“C++ 主义”,因此不喜欢它。
几乎没有理由重写 Linux 内核来进行不提供性能提升的外观更改。
如果代码库正常工作,那么为什么要出于美观的原因对其进行更改?
我不记得内核代码风格指南中对此有任何禁止。但是,它确实说函数应该尽可能小,并且只做一件事。这可以解释为什么声明和代码的混合很少见。
在一个小函数中,在作用域的开头声明变量就像一种Introit,告诉你一些关于即将发生的事情。在这种情况下,变量声明的移动非常有限,以至于它可能没有任何效果,或者通过将吠叫者推入人群来隐藏有关功能的一些信息,可以这么说。在进入房间之前就宣布国王的到来是有原因的。
OTOH,一个必须混合变量和代码才能读取的函数可能太大了。这是函数的某些部分需要抽象为单独的函数(并声明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
被定义两次。“所以?删除第二个声明。” 你说。但这会使代码不对称,最终会遇到更多的重构限制。
当然,我自己混合声明和编码;没有理由对此持教条主义(否则你的业力可能会超越你的教条:-)。但是你应该知道伴随的问题是什么。
没有任何好处。在函数开头声明所有变量(类似帕斯卡)更加清晰,在 C89 中,您还可以在每个作用域的开头声明变量(内部循环示例),这既实用又简洁。
也许不需要,也许分离是好的?我是用 C++ 做的,它也有这个特性。
没有理由像这样更改代码,C99 仍然没有得到编译器的广泛支持。它主要是关于便携性。