条件初始化是如何处理的?这是一个好的实践吗?

10

我正在考虑几种可能的做法。比如说,我的函数有许多if()块,它们在数据上工作,这些数据对它们来说是独特的。

  • 我应该在块内部声明和初始化局部数据吗?这会导致运行时性能成本(由于在堆栈中运行时分配)吗?

  • 还是应该在函数入口处声明和/或初始化所有变量,以便在一个可能更快的操作块中完成?

  • 还是应该将if()块分离成不同的函数,即使它们只有几行代码并且只在程序中使用一次?

还是我忽略了另一个更加清晰的选项?当前的问题是否可以回答?

5个回答

10

我是否应该在块内声明和初始化局部数据?

绝对是的:这可以使程序更易读。

这样做会有运行时性能成本(由于在堆栈中运行时分配)吗?

不会:所有的分配都是预先完成的——在进入函数时,堆栈上的空间已经被保留给了所有分支中的变量,而不是在进入分支时才进行分配。此外,这甚至还可以节省一些空间,因为编译器可以重复使用非重叠分支中分配给变量的空间。

或者我应该在函数入口处声明和/或初始化所有变量,以便在一个、可能更快的操作块中完成?

不,这不会更快,而且可能浪费一些空间。

或者我应该将 if() 块分开放在不同的函数中,即使它们只有几行,而且在程序中只使用了一次?

那可能会对程序的可读性产生负面影响。


请问您能否提供“所有分配都是预先完成的”这一说法的来源和/或解释?我曾经认为C语言很小而且无聊,但现在正在改变我的想法! - Vorac
1
更准确地说,这些分配和初始化是由编译器决定最有效的方式来完成的。 - Stephen Canon
我认为,这与Mohit的回答相矛盾,即局部变量在作用域内且已经初始化,并不意味着为其分配了空间,即编译器自由地重用不再被引用的变量的空间,直到变量作用域结束。 - Vorac
3
@Vorac这里没有矛盾 - 他所说的是编译器可以足够聪明地找出非重叠作用域,并且甚至在你不把声明放在非重叠块中时也能重用内存。这就是为什么我在回答中小心地使用了“可能会节省”而不是“一定会节省”的原因。 - Sergey Kalinichenko

4

尽可能保持 变量范围 较小是一个好的实践。
如果你一次性在开始时声明所有变量,并且在程序中不经常使用它们,那么这没有用,会占用更多的内存。

此外,保持作用域较小的另一个优点是可以再次重复使用相同的名称。(您不必每次执行琐碎的操作时都发明新名称)。


0

在你提出的选项中,声明并初始化块内部的局部数据是能够满足你目的的最好方法。忘记其他的事情。


0

为了完整性,另一个通常不太重要但需要考虑的问题是堆栈填充控制/打包,如果您没有事先声明所有内容,则这更难以直观理解。

请参见this获取更多信息,但在任何人做任何疯狂的事情之前,请让我强调以下段落:

通常,在您的C程序中,标量变量数量很少,通过改变声明顺序来获得的几个字节并不能节省足够的空间。当应用于非标量变量(尤其是结构体)时,该技术变得更加有趣。


尽管许多编译器可能按照您定义的顺序在堆栈上排列变量,但C标准并不要求它们这样做。有些编译器甚至可能为您完成此操作(但我不确定)。 - cmaster - reinstate monica
@cmaster:这是一个很好的观点,谢谢。对于好奇的人:[1](http://stackoverflow.com/q/4264896),[2](http://stackoverflow.com/q/9535342),[3](https://dev59.com/YnVC5IYBdhLWcg3wnCf6),[4](http://stackoverflow.com/q/1850556),[5](https://dev59.com/mHNA5IYBdhLWcg3wEpgU),[6](ftp://gcc.gnu.org/pub/gcc/summit/2003/Optimal%20Stack%20Slot%20Assignment.pdf)。我想我的观点是无意义的。 - tne

0

现在来谈论性能问题。

我应该在块内部声明和初始化本地数据吗?这会有运行时性能成本(由于在堆栈中运行时分配)吗?

本地变量的分配几乎是免费的。在大多数情况下,它确实是免费的,因为堆栈指针的更新是在将值写入堆栈的同一条指令中执行的。释放也是免费的(当从堆栈中弹出某些内容时),或者在返回时进行一次(当创建了一个堆栈帧时)。

还是我应该在函数入口处声明和/或初始化所有变量,以便在一个可能更快的操作块中完成?

虽然分配几乎是免费的,但运行构造函数/析构函数不是。虽然这不适用于原始类型的变量,但它适用于几乎所有用户定义的类型,包括智能指针等。如果您在函数开头声明一个智能指针,但只使用一半的时间,则会构造并随后销毁两倍于所需的智能指针。

此外,如果您声明一个变量,并且已经有了初始化它所需的信息,那么您可以直接构造它以达到您想要的状态,而不是先默认构造它,然后再使用赋值运算符在许多情况下更改其值。因此,从性能的角度来看,您应该尽可能晚地声明变量,并且仅在需要它们的块中声明。
“或者我应该将if()块分开放在不同的函数中,即使它们只有几行代码并且在程序中只使用一次吗?”
不,从性能的角度来看,这完全是适得其反的。每个函数调用都有开销,我认为大多数情况下在10到20个周期之间。在那段时间内,您可以进行相当多的计算。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接