C指针与结构的直接成员访问

假设我有一个类似以下的结构……

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

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

 double LocalSpeed = MyGlobal.MaxSpeed; 

要么

 double LocalSpeed = pMyGlobal->MaxSpeed; 

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

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

 double LocalSpeed = MyGlobal.MaxSpeed; 

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

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

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

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

 mov eax, [address of MyGlobal.MaxSpeed] 

而第二个就是这样的

 mov ebx, [address of pMyGlobal] mov eax, [ebx+sizeof(int)] 

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

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

 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)] 

拆卸,拆卸,拆卸……

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

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] 

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

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

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

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

在C中,应该没有差别,或者性能影响不大。

C学生被教导:

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

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

如果您正在寻找性能优化,我会寻找其他地方。 使用这种微优化,您将无法保存足够的CPU周期。

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

直接成员访问速度更快(对于指针,您通常会更多地获得一个指针解除引用操作)。 虽然我很难想象它会出现问题,表现或其他问题。