为什么使用指针(优化程度较低)会使程序更快?

时间:2019-04-30 21:56:43

标签: c assembly arm embedded iar

我正在学习有关嵌入式C编程的教程,然后意识到,使用指针指向变量,然后使用它取消引用可以使程序更快!

我具有汇编的基本知识,但是我没有弄清楚为什么将变量的地址分配给指针会更快,我们不是在谈论按引用,按指针或按值传递!

据我所知

  • 不带指针的代码:内存地址已分配给寄存器R0, 就像指针中的代码一样。
  • p_int成为寄存器R0的别名,这如何帮助提高程序速度?

不使用指针的代码:

int counter = 0;
int main() {
    while (counter < 6) {
        ++(counter);
    }
    return 0;
}

然后,该程序集将类似于enter image description here

相反,这是带有指针的代码:

int counter = 0;
int main() {
    int *p;
    p = &counter;
    while (*p < 6) {
        ++(*p);
    }
    return 0;
}

然后,该程序集将类似于enter image description here


更新

我与课程创建者联系,他很乐意为我重播和分解该课程,为了帮助可能遇到相同问题的其他人,我将保留问题和答案

  

要访问内存中的变量,CPU需要此地址   寄存器之一中的变量。在最低级别的代码   优化,编译器从代码存储器中加载该地址   在每次访问变量之前。指针速度   这是因为作为main()函数内部的局部变量是   分配给寄存器。这意味着该地址位于   寄存器(在这种情况下为R0),不需要加载,并且   每次都重新加载到寄存器中。在更高的优化水平   编译器会生成更明智的代码,而没有   指针和指针一样快。 -彩信

4 个答案:

答案 0 :(得分:3)

通常:没有任何理由使用指针会使程序运行得更快。与课程创建者在您的报价中所做的一样,讨论未启用所有优化的程序的性能是没有意义的。当然,这不是更改代码编写方式的原因。

另一个经常使用但过时的技巧是编写诸如递减计数而不是递增计数的循环,因为与零的比较通常比与值的比较更快。但这也不应该影响编写代码的方式,因为现代的编译器可以为您进行优化。

程序员应该做什么,以及编写课程的人们应该教什么,就是编写尽可能简单易懂的代码。这意味着您的两个示例都是不好的,因为它们不必要地晦涩难懂,并带有“过早优化”的示例。更好的代码是:

  int counter;
  ...
  for(counter=0; counter < 6; counter++)
  {}

这与代码获得的可读性差不多,没有理由相信以上内容在任何已知系统上的表现都将比您的示例差。

执行以下操作:

  • 写出最容易阅读的代码。
  • 在发行版中,启用优化。
  • 如果存在性能问题,请进行基准测试并找到瓶颈。
  • 根据需要手动优化瓶颈。可能考虑到特定的系统。

答案 1 :(得分:1)

在优化级别之间变化的任何编译器行为都是具体实现。因此,尽管已经向您展示了一些可能与直觉相反的演示,但是您不应该被教导这是因果关系。

以不同的方式编写代码可以总是触发性能提高或退化,并且不同的优化级别有时有时会导致错误的更改。显而易见,但是任何将较高的优化级别导致较差的性能(在本示例中不是这种情况)的情况都应视为编译器的问题。

答案 2 :(得分:0)

原始的更新提供了很好的答案。此外,在最初,“计数器”是一个全局变量,因此对ARM芯片的每次访问都需要先将变量加载到寄存器中。根据变量的位置和优化级别,这至少是一条LDR指令(可能更多),然后更新计数器++要求添加指令和写回全局变量。

如果将IF计数器声明为局部变量,那么实际上,使用指针版本将不是最佳选择。在这种情况下,大多数编译器会将计数器分配到寄存器中,然后对其进行访问将非常快。如果使用了指针,则将强制将计数器分配给堆栈(因为其地址已分配给“ p”),并且将需要更多指令来进行添加和访问。

答案 3 :(得分:-2)

它正好相反(几乎相同,但还有一条指令:):

https://godbolt.org/z/xDYecQ

enter image description here