我正在阅读一些C代码:
double function( int lena,double xa,double ya, double za, double *acoefs, ...,
int lenb,double xb,double yb, double zb, double *bcoefs, ...,
same for c,
same for d )
此函数在代码中被调用超过100.000次,因此它对性能至关重要。
我正在尝试扩展此代码,但我想知道它是否有效(以及这会影响速度)将所有参数封装在这样的结构中
struct PGTO { int len; double x,y,z ; double *acoefs }
然后访问函数中的参数。
答案 0 :(得分:5)
这个问题的答案在很大程度上取决于平台及其调用约定。它还取决于函数是否可以内联和其他编译器优化。
我会说,在许多平台上,struct版本可能更有效,因为如果要将指针传递给结构体,则要复制到堆栈的参数会更少。
无论如何,这个问题不容易回答。因此,与所有性能考虑一样:只需测试和配置文件!
答案 1 :(得分:5)
首先,在这种情况下,使用结构似乎是正确的方法。代码将更容易阅读和unerstand,它也将变得不那么混乱。
将指针传递给结构通常比传递大量参数便宜。
答案 2 :(得分:5)
Visual C ++ 2008 64位似乎通过让调用者为其堆栈上的结构副本分配空间并将数据项复制到其中然后将该副本的地址按值传递到函数中来传递结构。
这个简单的例子编译如下 -
struct data {
int a;
int b;
int c;
char d;
float f;
};
double f2(data d)
{
return d.a+d.b+d.c+d.d+d.f;
}
编译到此 -
movsx eax, BYTE PTR [rcx+12]
add eax, DWORD PTR [rcx+8]
add eax, DWORD PTR [rcx+4]
add eax, DWORD PTR [rcx]
movd xmm0, eax
cvtdq2ps xmm0, xmm0
addss xmm0, DWORD PTR [rcx+16]
unpcklps xmm0, xmm0
cvtps2pd xmm0, xmm0
ret 0
所以基本上当你传递单个项目时,调用者将它们推入堆栈,函数会相对于堆栈访问它们。当你传递一个strcuture时,调用者将数据项复制到堆栈中的一块内存中,然后将其地址传递给函数,该函数将相对于它访问它们。
第二种方法有更多的汇编语言指令,但是就我而言,从我的测试中可以看出,除了几微秒外,两种方法之间的效率没有显着差异。在我的所有测试中,编译器都希望内联任何调用,除非我强制它通过指针调用它,所以无论如何都可能在你的真实程序中没有任何东西通过堆栈传递。
在我看来,使用结构更清晰,速度似乎没有显着差异所以去那个:)
与往常一样,如果对性能有疑问,您需要分析您的确切设置
答案 3 :(得分:1)
我认为这取决于你填写结构的频率。
将单个指针传递给结构(4个字节)将比传递int,3个双精度和指针(32个字节)所需的指令少,但是如果在执行调用之前必须用这32个字节填充结构那你就失去了优势。
无论如何,性能始终是相对的,因此判断它是否值得的唯一方法是查看传递这些参数所花费的时间百分比。要做到这一点,我只是让它运行并随机暂停10或20次。除非我超过10%的时间通过这些论点,否则可能会有更大的问题可以先解决。
答案 4 :(得分:0)
现代编译器很可能在两种情况下都会生成相同的代码。因此,除非您的编译器不是最先进的,否则结构的唯一(但重要的)好处是提高了可读性。
答案 5 :(得分:0)
最好的事情是剖析和测试。
但是,有一点,当您将指针传递给struct时,较小的参数将被复制到堆栈中。此外,您的函数调用可能看起来更整洁。
答案 6 :(得分:0)
是的,他们是。如果我有那么多,我会打赌一百万美元,性能差异可以忽略不计。
答案 7 :(得分:0)
传递结构或参数列表不应该产生很大的不同。调用约定要求两者都通过值传递并通过堆栈传递(除非函数可以声明为static
)。
您可以重构代码以启用pass-by-reference(将指针传递给struct)。但这可能是一个重大的重新设计,它可能会使您的代码更复杂,更不易读。