分配还是传递缓冲区?

时间:2012-04-25 22:55:34

标签: c performance struct compiler-optimization

假设 buffer 是由几个成员组成的结构,包括一个数组。

使用通常的优化标记进行编译,运行这两个代码片段应该会产生什么样的性能差异?

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);
}

2 个答案:

答案 0 :(得分:3)

第一个答案是:基准测试。

第二个答案是:将它们编译为汇编语言,然后查看源代码。使用和不使用标志符号执行此操作可能具有指导意义。

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

所以我希望在第二种情况下生成的代码中的主要区别是少一个“PUSH”指令,假设有足够的参数,有些必须进入堆栈。 (如果它们都在寄存器中,那就有点不同了。)

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

请注意,基于查看编译器的行为,以上是我的猜测。从理论上讲,只要生成的程序运行正常,编译器就可以翻译代码,这使得很难概括他们可能做或不做的优化。

答案 1 :(得分:0)

@TJD的评论是正确的。

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

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

init实际上没用,因为完成的所有工作都已丢失,并且在调用函数中不可见。

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