2012-04-25 86 views
2

假设缓冲区是由若干成员组成的结构,包括一个数组。分配或传递缓冲区?

使用通常的优化标志进行编译,应该期望运行这两个代码片段会带来怎样的性能差异?

buffer buf; 
for (int i = 0; i < BIG_ENOUGH_NUMBER; i++) { 
    init(huge_file, i, &buf); 
} 

// buf is not used afterward 

... 

void init(FILE* f, int i, buffer* b) { 
    ... // b is filled using f, according to i 
    do_something(b); 
} 

VS

for (int i = 0; i < BIG_ENOUGH_NUMBER; i++) { 
    init(huge_file, i); 
} 

... 

void init(FILE* f, int i) { 
    buffer buf; 
    ... // buf is filled from scratch using f, according to i 
    do_something(&buf); 
} 
+0

每个迭代中保留或重建'buf'中的多少数据/状态? – sarnold 2012-04-25 22:59:53

+0

第二个例子没有声明b?这应该是buf吗? – TJD 2012-04-25 23:00:04

+0

更正完成。 – Rhangaun 2012-04-25 23:01:39

回答

3

第一个答案是:基准他们。

第二个答案是:将它们编译为汇编语言,然后查看源代码。做到这一点与无标志可能是有益的。

正如指出的那样,在这两种情况下,buf都在堆栈中。我的一般猜测是,第二种情况会稍微快一点(对于我使用的编译器),因为buf不必作为参数传递。它必须在堆栈上进行分配,但堆栈分配通常只是函数调用帧的稍微不同的大小。无论该框架有多大,都必须完成相同数量的工作(调整堆栈指针)。

所以我希望在生成代码的主要区别是在第二种情况下少了一个“PUSH”的说明,假设有足够的议论,有些将不得不在堆栈中。 (如果它们都在寄存器中,则有点不同)。

它可能受优化影响,例如buf是否在每种情况下都以寄存器结尾。但缺少填充buf的代码可能会影响到这一点,所以我不会推测。

请注意,以上是我基于查看我的编译器的行为的猜测。从理论上讲,编译器可以转换代码,只要结果程序运行正确,这使得很难概括它们可能做什么或者不可以做什么优化。

0

@TJD是在他的评论是正确的。

在这两种情况下,buf都在堆栈中,如果它很大,有可能导致问题。 您通常应该使用malloc从堆分配大型项目。

这就是说,在你的第二个例子中,buf完全在init函数内,并且在函数返回给调用者的那一刻消失(在你的例子中调用者未被命名)。

init是无效的,因为所做的所有工作都已丢失,并且在调用函数中不可见。

在第一个示例中,在init返回后buf仍然有效。

+0

在这两种情况下,都会使用初始化的buf调用do_something。 – Rhangaun 2012-04-25 23:05:50