Arduino - 通过指针传递struct似乎比按值慢

时间:2016-01-04 18:10:24

标签: c++ arduino

我写了一些伪代码,可以解释我在实际应用中发现的问题(Arduino 1.6 - https://github.com/maciejmiklas/LEDDisplay):

Display.h:

class Display {

public:
    void testRef();
    void testVal();

private:
    typedef struct {
            uint8_t xOnFirstKit;
            uint8_t yOnFirstKit;
            uint8_t xRelKit;
            uint8_t yRelKit;
            uint8_t xRelKitSize;
            uint8_t yRelKitSize;
            uint8_t xDataBytes;
            uint8_t xKit;
            uint8_t yKit;
            uint8_t xOnKit;
            uint8_t yOnKit;
            uint8_t xOnKitSize;
            uint8_t yOnKitSize;
            uint8_t xOnScreenIdx;
            uint8_t yOnScreenIdx;
            uint8_t yDataIdx;
        } KitData;

 inline void paintOnKitRef(KitData *kd); 
 inline void paintOnKitVal(KitData kd); 
}


Display.cpp:

#include "Display.h"

void Display::testRef(){
    KitData *kd = ....

    for(int i = 0 ; i < 5000 ; i++){
       paintOnKitRef(kd);
       ....
    }
}

void Display::testVal(){
    KitData *kd = ....

    for(int i = 0 ; i < 5000 ; i++){
       paintOnKitVal(*kd);
       ....
    }
}

inline void Display::paintOnKitRef(KitData *kd){
    for(int i = 0 ; i < 100 ; i++){
        kd->yDataIdx++;
        kd->yOnScreenIdx++;
        .....
    }
}

inline void Display::paintOnKitVal(KitData kd){
    for(int i = 0 ; i < 100 ; i++){
        kd.yDataIdx++;
        kd.yOnScreenIdx++;
        .....
    }
}

我有结构:KitData大于16个字节,所以我决定用指针而不是值传递它 - 它按预期工作。

我已经测量了执行时间,看起来像传递值(testVal())比通过引用(testRef())传递快30%。

这是正常的吗?

修改

上面的代码只是一个伪代码 - 在我的实际测试方法中:paintOnKitVal()paintOnKitRef()包含执行许多操作和其他方法的实际代码。这两种方法也做同样的事情 - 唯一的区别是访问kd(通过指针或点表示法)。

这是真正的测试类:https://github.com/maciejmiklas/LEDDisplay/blob/callByPoint/Display.cpp

  1. 执行测试方法:paint(...) - 这将使用第211行中的call-by-pointer
  2. 注释第211行并从第212行删除注释 - 从现在开始测试将使用按值调用,执行时间将缩短。

2 个答案:

答案 0 :(得分:5)

这部分代码绝对没有任何内容,优化器会认识到:

inline void Display::paintOnKitVal(KitData kd){
    for(int i = 0 ; i < 100 ; i++){
        kd.yDataIdx++;
        kd.yOnScreenIdx++;
    }
}

您认为您测试了传递值的性能。但是你真的测试了编译器识别代码什么都不做的事实的能力。

当您通过指针(C程序员可能通过引用调用“但C ++程序员不会”通过引用“)时,单独的函数不能说什么都不做。优化器需要更广泛地理解检测缺乏效果的整个程序。

答案 1 :(得分:3)

传值和传递参数之间的差异:

传递通过值:

void foo(int a) {
  a = 30; // passed in param is now 30 until end of scope
}

int main() {
  int b = 3;
  foo(b); // copy of b is made, copy is assigned value 30
  // b is still 3
}

传递通过引用:

void foo(int& a) {
  a = 30; // passed in param is now 30 because a reference was passed in
}

int main() {
  int b = 3;
  foo(b); // reference to b is assigned value 30
  // b is now 30
}

传递指针类似以传递引用,但有一些差异outlined here

您为testVal撰写的代码将在kd的副本上执行操作。这不是你想要的。

对于小结构,传递值和传递引用的速度将类似。 然而,内存占用量将大不相同。每次传递内容时,按值传递都会复制,这将占用大量内存。

至于为什么它更快:

There are likely optimizations因为正在制作副本而不是对编译器为您制作的传入对象的实际更改。但是,这是以错误算法为代价的。

在传递值后,更改将不会反映在传入的kd中。指针&#39;变化将反映出来并且是正确的。