繁体   English   中英

C代码优化查询

[英]C code optimization query

我有一个关于遵循 C 代码的问题。

struct pqr {
  int b;
};

struct abc {
  int a;
  struct pqr * ptr2;
};

struct abc *ptr1;

ptr1->ptr2->b = 10;

现在,如果我在函数中有几行带有 ptr1->ptr2 取消引用的代码,以下代码更改是否有助于减少 CPU 周期?

   struct pqr *ptr = ptr1->ptr2;

   ptr->b = 10;

显示的代码不足。

如果这一切都在一个功能中,它应该没有区别。 如果您将struct pqr两个传递给函数,则需要进行跨函数/模块别名分析,以确定缓存指针是否保留了程序语义。

这取决于编译器,但一些已知的编译器将从代码中的这种显式优化中受益。

对于此示例代码:

int getValue() {
  return rand();
}

void testA() {
  ptr1->ptr2->b = getValue();
  ptr1->ptr2->b = getValue();
  ptr1->ptr2->b = getValue();
}

void testB() {
  struct pqr *ptr2 = ptr1->ptr2;
  ptr2->b = getValue();
  ptr2->b = getValue();
  ptr2->b = getValue();
}

带有 -O3 的GCC 6.3Clang 3.9.1都将生成类似于以下内容的程序集:

testA():
        mov     rax, QWORD PTR ptr1[rip]
        mov     rbx, QWORD PTR [rax+8] // load
        call    rand            
        mov     DWORD PTR [rbx], eax   // store

        mov     rax, QWORD PTR ptr1[rip]
        mov     rbx, QWORD PTR [rax+8]  // load
        call    rand            
        mov     DWORD PTR [rbx], eax  // store

        mov     rax, QWORD PTR ptr1[rip]
        mov     rbx, QWORD PTR [rax+8]  // load
        call    rand            
        mov     DWORD PTR [rbx], eax  // store


testB():
        mov     rax, QWORD PTR ptr1[rip]
        mov     rbx, QWORD PTR [rax+8]   // load

        call    rand
        mov     DWORD PTR [rbx], eax  // store

        call    rand
        mov     DWORD PTR [rbx], eax  // store

        call    rand
        mov     DWORD PTR [rbx], eax  // store

在非优化编译器上,这会有所帮助。 但是在带有优化标志的现代编译器中,您不应该看到这两种语法之间的区别。

不,这样的代码不会提高性能。 任何半体面的编译器都会优化掉那个临时变量。 您的任何版本都将编译为机器代码,如下所示:

将 ptr1->ptr2 存储在索引寄存器 x 中
...
对索引寄存器 x 指向的内容进行处理
...
// 相同变量的后续使用将使用索引寄存器 x


但是,如果您打算在多个表达式中大量使用该嵌套结构,则您的临时变量可以提高可读性。 替换代码如

something->something->something->x = 5;
if(something->something->something->x == something->something->something->y)
  something->something->something->y = 42;

something_t* s = something->something->something;
s->x = 5;
if(s->x == s->y)
  s->y = 42;

是相当的可读性的提高。 但它会产生完全相同的机器代码。

对于您所提供的情况,编译器将输出多少条指令取决于优化程度(但在这里您假设没有?)、您的编译器的智能程度以及处理器的类型(例如 CISC 或 RISC)。 正如你所知道的,这里有太多的变数无法得到答案。 您需要反汇编并查看不同版本的代码是否会生成包含更多或更少指令的编译(并且仅针对有问题的代码行)。

但通常在过去,建议总是如果您在循环内或在循环内调用的函数内执行任何形式的“间接”,则应避免任何形式的“间接”。 原因是编译器可能会实现许多操作以解决间接问题 - 因此,即使它看起来不像您严格取消引用 C 代码中的指针,编译器也会生成可以执行的程序集 - 如果您希望使用任何结构成员。 因此,在您的情况下,它需要解决两个间接级别而不是一个级别(替代方法:ptr->b)。

我认为这将有助于减少 CPU 周期。 ptr是指针变量,编译时无法计算ptr1->ptr2值。 至少可读性更好(使用ptr )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM