11

假设我有一个如下结构......

typedef struct {
  int WheelCount;
  double MaxSpeed;
} Vehicle;

...而且我有一个这种类型的全局变量(我很清楚全局变量的陷阱,这是针对嵌入式系统的,我没有设计它,它们是不幸但必要的邪恶。 ) 直接或通过指针访问结构的成员是否更快?IE

double LocalSpeed = MyGlobal.MaxSpeed;

或者

double LocalSpeed = pMyGlobal->MaxSpeed;

我的任务之一是简化和修复最近继承的嵌入式系统。

4

9 回答 9

21

一般来说,我会说第一个选项:

double LocalSpeed = MyGlobal.MaxSpeed;

这减少了一个取消引用(您没有找到指针,然后取消引用它以到达它的位置)。它也更简单,更易于阅读和维护,因为除了结构之外您不需要创建指针变量。

话虽如此,我认为您看到的任何性能差异都不会很明显,即使在嵌入式系统上也是如此。两者都将是非常非常快的访问时间。

于 2009-08-25T15:40:07.117 回答
8

第一个应该更快,因为它不需要指针取消引用。那么对于基于 x86 的系统也是如此,对于其他系统则不确定。

在 x86 上,第一个会翻译成这样的东西

mov eax, [address of MyGlobal.MaxSpeed]

第二个是这样的

mov ebx, [address of pMyGlobal] 
mov eax, [ebx+sizeof(int)] 
于 2009-08-25T15:40:57.613 回答
3

在您的嵌入式平台上,架构很可能以这样一种方式进行了优化,它本质上是一种清洗,即使不是这样,如果在一个非常紧密的循环中执行,您也只会注意到性能影响。

您的系统可能有更明显的性能区域。

于 2009-08-25T15:46:42.000 回答
3
struct dataStruct
{
    double first;
    double second;
} data;

int main()
{
    dataStruct* pData = &data;

    data.first = 9.0;
    pData->second = 10.0;
}

这是使用 VS2008 发布模式的程序集输出:

    data.first = 9.0;
008D1000  fld         qword ptr [__real@4022000000000000 (8D20F0h)] 

    pData->second = 10.0;
008D1006  xor         eax,eax 
008D1008  fstp        qword ptr [data (8D3378h)] 
008D100E  fld         qword ptr [__real@4024000000000000 (8D20E8h)] 
008D1014  fstp        qword ptr [data+8 (8D3380h)] 
于 2009-08-25T15:48:36.973 回答
2

拆机、拆机、拆机……

根据您没有向我们展示的代码行,如果您的指针有些静态,一个好的编译器可能会知道这一点并预先计算两者的地址。如果您没有优化,那么整个讨论都是无声的。它还取决于您使用的处理器,两者都可以使用一条指令执行,具体取决于处理器。所以我遵循基本的优化步骤:

1) 反汇编和检查 2) 计时执行

如上所述,尽管底线可能是两条指令的情况,而不是一条花费您可能永远不会看到的单个时钟周期的情况。你的编译器和优化器选择的质量将比试图调整一行代码以提高性能产生更大的性能差异。切换编译器可以在任一方向为您提供 10-20% 的收益,有时甚至更多。就像改变你的优化标志一样,打开所有东西并不能生成最快的代码,有时 -O1 比 -O3 执行得更好。

了解这两行代码产生了什么以及如何最大限度地提高高级语言的性能来自于为不同的处理器编译和使用各种编译器进行反汇编。更重要的是,有问题的行周围的代码在编译器如何优化该段方面发挥着重要作用。

在这个问题上使用别人的例子:

typedef struct
{
    unsigned int first;
    unsigned int second;
} dataStruct;

dataStruct data;

int main()
{
    dataStruct *pData = &data;

    data.first = 9;
    pData->second = 10;

    return(0);
}

使用 gcc(不是那么好的编译器),您将获得:

mov r2, #10
mov r1, #9
stmia   r3, {r1, r2}

所以两行 C 代码合并到一个存储中,这里的问题是用作测试的示例。两个单独的函数会更好一些,但是它需要更多的代码,并且指针需要指向其他一些内存,所以优化器没有意识到它是一个静态全局地址,要测试这个你需要传递地址因此编译器(以及 gcc)无法确定它是静态地址。

或者没有优化,相同的代码,相同的编译器,指针和直接之间没有区别。

mov r3, #9
str r3, [r2, #0]

mov r3, #10
str r3, [r2, #4]

根据编译器和处理器,这是您期望看到的,可能没有区别。对于这个处理器,即使测试代码从函数中隐藏了指针的静态地址,它仍然可以归结为两条指令。如果存储在结构元素中的值已经加载到寄存器中,那么它将是一条指令,无论是指针还是直接指令。

所以你的问题的答案不是绝对的......这取决于。拆卸和测试。

于 2009-08-27T14:06:24.947 回答
1

我想,如果这有什么不同,那将取决于架构。

于 2009-08-25T15:38:36.947 回答
1

在 C 中,应该没有区别,或者对性能的影响很小。

C 学生被教导:

pMyGlobal->MaxSpeed == (*pMyGlobal).MaxSpeed

即使您不是汇编代码程序员,您也应该能够比较它们的反汇编来说服自己它们本质上是相同的。

如果您正在寻找性能优化,我会寻找其他地方。通过这种微优化,您将无法节省足够的 CPU 周期。

出于文体原因,我更喜欢 Structure-Dot 表示法,尤其是在处理单例全局变量时。我觉得阅读起来更干净。

于 2009-08-25T15:40:29.597 回答
1

一般来说,直接访问结构会更快,因为它不需要额外的指针取消引用。指针取消引用意味着它必须获取指针(变量中的东西),加载它指向的任何内容,然后对其进行操作。

于 2009-08-25T15:41:11.683 回答
0

直接成员访问更快(对于指针,您通常会获得更多的指针取消引用操作)。尽管我很难想象它会出现问题、性能或其他方面的情况。

于 2009-08-27T14:12:30.040 回答