11

假设我有一个重复数百万次的循环。在这个循环里面我有一个函数调用。

在这个函数内部,我需要对一开始创建的一些临时变量进行操作。现在,哪个更好:

a) 在代码开头创建临时变量,在循环开始时对其进行初始化,并将其作为函数参数传递

b) 在被调用函数的开头仅创建局部临时变量?

这是可以回答的问题吗?我想知道哪一点被认为是更好的做法,或者哪一点更快。

4

3 回答 3

9

让我们抛出一些可能的定义some_function(),您将从循环中调用的函数。

// Method 1
void some_function() {
    int temporary;

    // Use temporary
}

// Method 2
void some_function(int temporary) {
    // Use temporary
}

// Method 3
void some_function(int *temporary) {
    // Use *temporary
}

方法 1 可能是这些选项中最易读的,所以除非你有充分的理由去做其他事情,否则我会更喜欢它。它也可能比其他任何一个都快,除非您的编译器内联函数调用。如果是,那么所有三个可能执行完全相同(如果编译器无法优化指针取消引用,方法 3 可能仍然较慢)。

如果编译器没有内联,那么方法 2 可能比方法 1 慢。这是因为,就堆栈分配的内存而言,它们是相同的——函数参数将以相同的方式存储在堆栈中当地人是。在这种情况下,函数参数和局部变量之间的唯一区别是函数参数可以由调用者赋予一个值。将值从调用者传输到函数的这一步骤(理论上)会减慢调用速度。

方法 3 几乎肯定会更慢,因为对临时内存的访问将包括一定程度的间接性。与访问本地相比,取消引用指针并不是一项廉价的操作。

当然,如果性能绝对至关重要,那么您应该对这些方法进行基准测试。我怀疑方法 1 会是最快的(或者至少不会比其他方法慢),而且对我来说似乎更具可读性。

于 2013-04-09T16:47:56.433 回答
1

如果该变量在函数外部不需要,那么它应该在函数内部。这允许编译器在优化代码方面做得最好,并使代码最易读和易于使用(这通常适用于“声明具有最小可能范围的变量”,尽管对于小函数,声明少数每次在函数顶部的变量是最好的选择)。

从性能的角度来看,将变量传递给函数要么等效,要么比具有局部变量更差。[当然,编译器可能会内联所有内容,并且在两种情况下您最终都会得到完全相同的代码,但这取决于编译器和您拥有的代码]。

正如其他人所提到的,将指针传递给局部变量将导致访问指针以获取值的“惩罚”。它可能不会产生巨大的差异,但几乎可以肯定会产生一些差异。这绝对应该是最后的手段。[请注意,如果变量是 LARGE,则将副本传递给函数的开销可能仍然比指针的开销更糟。但是如果我们假设它是一个简单的类型,比如intor float,那么指针就会有明显的开销]。

任何时候有关于性能的问题,你肯定应该对你的代码进行基准测试。如果在排序算法或类似的算法之间有选择,在互联网上询问其他人可能是值得的,但如果在一些更细微的差异中是“这样做或那样做更好”的情况,那么差异通常是小,您的特定编译器所做的将比“理论上更好”产生更大的影响。

于 2013-04-09T16:59:17.137 回答
0

如果您将变量作为指针而不是值传递,这两种方法之间存在细微差别。指针将被压入调用堆栈,并且必须被引用才能获取/设置值。

相反,将其设置为本地值,或按值传递,会将值放入堆栈。在这种情况下,它是局部变量还是按值传递并不重要......尽管在按值传递的情况下,根据变量在函数外部的处理方式有一个可能的警告......如果它存储在一个变量(不传递文字值)然后它必须从内存中获取并推送到堆栈上。如果它是从函数内部的文字值设置的,它只是一个压入堆栈的文字并节省了一个内存周期。

您省略的第三个选项是使用全局变量。

如果值始终保持不变,那么最好的答案是使用 #define 并将其作为文字直接编译到代码中。

于 2013-04-09T16:48:12.830 回答