C结构指针解除引用速度

时间:2010-10-21 11:18:49

标签: c++ c pointers local dereference

我对指针解除引用的速度有疑问。我有这样的结构:

typedef struct _TD_RECT TD_RECT;
struct _TD_RECT {
  double left;
  double top;
  double right;
  double bottom;
};

我的问题是,哪一个更快,为什么?


案例1:

TD_RECT *pRect;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < pRect->left) ...
   if(p[i].x > pRect->right) ...
   if(p[i].y < pRect->top) ...
   if(p[i].y > pRect->bottom) ...
}

案例2:

TD_RECT *pRect;
double left = pRect->left;
double top = pRect->top;
double right = pRect->right;
double bottom = pRect->bottom;
...
for(i = 0; i < m; i++)
{
   if(p[i].x < left) ...
   if(p[i].x > right) ...
   if(p[i].y < top) ...
   if(p[i].y > bottom) ...
}

因此,在情况1中,循环直接取消引用pRect指针以获取比较值。在第2种情况下,在函数的局部空间(堆栈上)上创建了新值,并将值从pRect复制到局部变量。通过循环会有很多比较。

在我看来,它们同样会很慢,因为局部变量也是堆栈上的内存引用,但我不确定......

此外,最好继续通过索引引用p [],或者将p递增一个元素,并在没有索引的情况下直接取消引用它。

有什么想法吗?谢谢:))

5 个答案:

答案 0 :(得分:12)

您可能会发现它对现代编译器没有任何影响。他们中的大多数可能会执行常见的subexpresion消除循环内不会改变的表达式。假设C语句和汇编代码之间存在简单的一对一映射,这是不明智的。我见过gcc泵出代码会让我的汇编技能感到羞耻。

但这既不是C也不是C ++问题,因为ISO标准并未强制要求如何完成。检查确保的最佳方法是使用类似gcc -S的内容生成汇编代码,并详细检查这两种情况。

如果你避开这种微优化并且更多地关注宏观层面,例如算法选择等,你也会获得更多的投资回报。

并且,与所有优化问题一样,测量,不要猜测!有太多的变量会影响它,所以你应该在目标环境中对不同的方法进行基准测试,并且具有真实性数据

答案 1 :(得分:3)

它不太可能是一个巨大的性能关键差异。您可以多次配置每个选项并查看。确保在测试中设置了编译器优化。

关于存储双打,使用const可能会影响性能。你的阵列有多大?

关于使用指针运算,这可能更快,是的。

如果你知道左边&lt;你可以立即优化。在你的矩形(当然必须)。如果x <离开它不能也是&gt;是的,所以你可以放入“其他”。

你的大优化(如果有的话)来自于不必遍历数组中的所有项目而不必对所有项目执行4次检查。

例如,如果您在x和y上对数组建立索引或排序,则可以使用二进制搜索来查找x&lt;离开并循环通过那些。

答案 2 :(得分:1)

我认为第二种情况可能会更快,因为你没有在每次循环迭代时取消引用指向pRect的指针。

实际上,执行优化的编译器可能会注意到这一点,并且生成的代码可能没有区别,但pRect是p []中项目的别名的可能性可能会阻止这种情况。

答案 3 :(得分:0)

优化编译器将看到结构访问是循环不变的,Loop-invariant code motion也是如此,使你的两个案例看起来是一样的。

答案 4 :(得分:0)

即使完全非优化的编译(-O0)会为所呈现的两种情况产生不同的代码,我也会感到惊讶。为了在现代处理器上执行任何操作,需要将数据加载到寄存器中。因此,即使您声明自动变量,这些变量也不会存在于主存储器中,而是存在于其中一个处理器浮点寄存器中。即使您没有自己声明变量也是如此,因此即使在C ++代码中声明临时变量时,我预计生成的机器代码也没有区别。

但正如其他人所说,将代码编译成汇编程序并亲自查看。