今天给同事复查代码时,我发现了一件奇怪的事情。他把他的新代码用大括号括起来,就像这样:
Constructor::Constructor()
{
// Existing code
{
// New code: do some new fancy stuff here
}
// Existing code
}
如果有结果的话,结果会是什么?这样做的原因是什么?这种习惯从何而来?
环境是嵌入式设备。有很多遗留的C代码被包裹在c++的外衣里。有很多C转向c++的开发人员。
在这部分代码中没有临界区。我只在这部分代码中看到过。没有完成主要的内存分配,只是设置了一些标志,并进行了一些操作。
用大括号括起来的代码是这样的:
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit) {
return isInit;
}
}
(不要介意代码,只要坚持花括号…,))
在花括号之后,还有更多的位处理、状态检查和基本信号。
我和他谈过,他的动机是限制变量的范围,命名冲突,以及其他一些我不能真正理解的东西。
从我的角度来看,这似乎很奇怪,我认为花括号不应该出现在我们的代码中。在所有关于为什么可以用花括号包围代码的回答中,我看到了一些很好的例子,但你不应该把代码分成方法吗?
fsdf
在编辑中查看代码后,我可以说不必要的括号可能(在原始编码器的视图中)100%清楚在if/then期间会发生什么,即使现在只有一行,以后可能会有更多行,括号保证你不会犯错误。
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit) {
return isInit;
}
return -1;
}
如果以上是原来的,删除“extras”将导致:
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit)
return isInit;
return -1;
}
然后,稍后的修改可能是这样的:
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit)
CallSomethingNewHere();
return isInit;
return -1;
}
当然,这会导致一个问题,因为现在isInit总是会被返回,不管if/then。
另一个使用的例子是与ui相关的类,尤其是Qt。
例如,你有一些复杂的UI和很多小部件,每个小部件都有自己的间距、布局等。不是命名为space1, space2, spaceBetween, layout1,…对于只存在于2 - 3行代码中的变量,可以避免使用非描述性的名称。
好吧,有些人可能会说你应该把它分成方法,但是创建40个不可重用的方法看起来不太好——所以我决定在它们之前添加大括号和注释,所以它看起来像逻辑块。
例子:
// Start video button
{
<Here goes the code >
}
// Stop video button
{
<...>
}
// Status label
{
<...>
}
我不能说这是最佳实践,但对于遗留代码来说是一个很好的实践。
当很多人把他们自己的组件添加到UI中,一些方法变得非常庞大时,就会出现这些问题,但在类中创建40个一次性使用的方法已经搞砸了,这是不现实的。
我同意ruakh。如果你想了解C语言中各种范围级别的解释,可以看看这篇文章:
C应用程序中不同级别的作用域
一般来说,如果您只想使用一个临时变量,而不必在函数调用的生命周期内跟踪该变量,那么使用“块作用域”是很有帮助的。此外,有些人使用它是为了方便在多个位置使用相同的变量名,尽管这通常不是一个好主意。例如:
int unusedInt = 1;
int main(void) {
int k;
for(k = 0; k<10; k++) {
int returnValue = myFunction(k);
printf("returnValue (int) is: %d (k=%d)",returnValue,k);
}
for(k = 0; k<100; k++) {
char returnValue = myCharacterFunction(k);
printf("returnValue (char) is: %c (k=%d)",returnValue,k);
}
return 0;
}
在这个特殊的例子中,我定义了两次returnValue,但由于它只是在块范围内,而不是函数范围内(例如,函数范围将在int main(void)之后声明returnValue),因此我不会得到任何编译器错误,因为每个块都不知道声明的returnValue的临时实例。
我不能说这在一般情况下是一个好主意(例如,您可能不应该从一个块到另一个块重复重用变量名),但一般来说,它节省了时间,并使您不必在整个函数中管理returnValue的值。
最后,请注意我的代码示例中使用的变量的范围:
int: unusedInt: File and global scope (if this were a static int, it would only be file scope)
int: k: Function scope
int: returnValue: Block scope
char: returnValue: Block scope