如果我有一个带有以下内容的 test.c 文件
#include ...
int global = 0;
int main() {
int local1 = 0;
while(1) {
int local2 = 0;
// Do some operation with one of them
}
return 0;
}
因此,如果我必须在 while 循环中使用其中一个变量,那么首选哪一个?
也许我在这里有点含糊,但我想知道时间/空间分配的差异是否真的相关。
如果我有一个带有以下内容的 test.c 文件
#include ...
int global = 0;
int main() {
int local1 = 0;
while(1) {
int local2 = 0;
// Do some operation with one of them
}
return 0;
}
因此,如果我必须在 while 循环中使用其中一个变量,那么首选哪一个?
也许我在这里有点含糊,但我想知道时间/空间分配的差异是否真的相关。
如果您想知道在 for 循环中声明一个变量是否会导致它在每次迭代时被创建/销毁,那么没有什么可担心的。这些变量不是在运行时动态分配的,malloc
这里什么都没有编辑——只是留出了一些内存供循环内部使用。因此,就性能而言,将变量置于内部与将其置于循环外部是一样的。
这里真正的区别是范围而不是性能。使用全局变量还是局部变量只会影响您希望该变量在何处可见。
如果您想知道性能差异:很可能没有。如果存在理论上的性能差异,您会发现实际上很难设计一个测试来测量它们。
像这样的决定不应该基于性能,而是基于语义。除非需要全局变量的语义行为,否则应始终使用自动(局部非静态)变量。
正如其他人所说并且肯定会说的那样,性能不太可能存在任何差异。如果有,自动变量会更快。
C 编译器将更容易对函数本地声明的变量进行优化。全局变量需要优化器来执行“过程间数据流分析”,这并不常见。
作为差异的示例,请考虑您的所有声明都将变量初始化为零。但是,在全局变量的情况下,编译器不能使用该信息,除非它验证程序中的任何控制流都不能在示例函数中使用它之前更改全局变量。对于本地声明的(“自动”)变量,初始值无法被另一个函数更改(特别是,编译器验证它们的地址从未传递给子函数)并且编译器可以执行“killed definitions”和“value liveness”分析以确定是否可以在某些代码路径中假定零值。
作为指导,在两个局部变量中,优化器总是更容易优化对具有更小(更有限)范围的变量的访问。
如上所述,我建议其他关于语义偏向于优化器元优化的答案是正确的。使用使代码可读性最好的变量,您将获得比协助 def-use 优化计算更多的时间回报。
通常,避免使用全局变量或任何可以比绝对必要更广泛地访问的变量。有限的变量范围有助于防止在以后的程序维护期间引入错误。
变量分为三大类:静态(全局)、堆栈(自动)和寄存器。
寄存器变量存储在 CPU 寄存器中。寄存器是速度非常快的字大小存储器,集成在 CPU 流水线中。它们可以免费访问,但数量非常有限(通常在 8 到 32 之间,具体取决于您的处理器和您正在执行的操作)。
堆栈变量存储在称为堆栈的 RAM 区域中。堆栈几乎总是在缓存中,因此堆栈变量通常需要 1-4 个周期才能访问。
通常,局部变量可以在寄存器中,也可以在堆栈中。它们是分配在函数顶部还是循环中都没有关系;每次函数调用它们只会被分配一次,并且分配基本上是免费的。如果可能,编译器会将变量放入寄存器中,但是如果您的活动变量比寄存器多,它们将不适合。此外,如果您获取变量的地址,它必须存储在堆栈中,因为寄存器没有地址。
全局变量和静态变量是不同的野兽。由于它们通常不会被频繁访问,它们可能不在缓存中,因此可能需要数百个周期才能访问它们。此外,由于编译器可能无法提前知道全局变量的地址,因此可能需要查找它,这也很昂贵。
正如其他人所说,不要太担心这些东西。知道这绝对是件好事,但它不应该影响您编写程序的方式。编写有意义的代码,让编译器担心优化。如果您进入编译器开发,那么您可以开始担心它。:)
编辑:有关分配的更多详细信息:
寄存器变量由编译器分配,因此没有运行时成本。生成值后,代码只会将值放入寄存器中。
堆栈变量由您的程序在运行时分配。通常,当一个函数被调用时,它要做的第一件事就是为它的所有局部变量保留足够的堆栈空间。所以没有每个变量的成本。