【问题标题】:Make all pointers in an array of pointers point to the same thing in C?使指针数组中的所有指针指向C中的同一事物?
【发布时间】:2015-03-05 16:12:25
【问题描述】:

我有这两个定义:

uint8_t *idx[0x100];
uint8_t  raw[0x1000];

除了遍历idx 的每个元素以将它们全部指向raw[0] 之外,还有其他方法吗?

for (i=0; i<sizeof(raw); i++)
    idx[i] = &raw[0];

肯定有比 ↑ 更快的方法。是否有与 memset 等效的指针?

【问题讨论】:

  • 没有别的办法。
  • 此外,您会以这种方式超出缓冲区 - sizeof() 为您提供数组的 bytes 大小,而不是数组计数。你想要for ( i = 0; i &lt; sizeof(idx) / sizeof(idx[0]); i++)(还要注意它是sizeof(idx),而不是sizeof(raw);
  • 如果静态分配raw,可以在编译时进行初始化。

标签: c performance pointers memory


【解决方案1】:

简单直接的循环可能是最好的方法(请注意,正如其他人指出的那样,您当前的循环中存在错误)。

优点是这类循环很容易优化,这是一种常见的情况,编译器已经非常擅长它,并且你的编译器将根据需要使用向量指令和其他优化来保持它非常快而不需要手动优化自己。 当然,同时它比手动优化更易读、更易于维护。

当然,如果有特殊情况,例如,如果你想用空指针填充它,或者如果你知道在编译时内容将是什么,那么有一些更有效的方法可以做到这一点,但在让编译器轻松优化代码的一般情况是获得良好性能的最简单方法。

【讨论】:

    【解决方案2】:

    从性能工程的角度来看,确实有办法让它比

    for (i=0; i<sizeof(raw); i++)
        idx[i] = &raw[0];
    

    如果在编译器中关闭优化器后进行比较。但差异可能非常小。

    让我们开始吧:

    uint8_t *idx[0x100];
    uint8_t  raw[0x1000];
    
    #define lengthof(arr)    (sizeof(arr) / sizeof(*arr))
    
    uint8_t *start = idx;
    int length = lengthof(idx);
    uint8_t *end = idx + (length & ~1);
    for (; start < end;)
    {
        *start++ = raw;
        *start++ = raw;
    }
    if (length & 1)
        *start++ = raw;
    

    这主要是因为两个原因更快:

    1. 直接操作指针。如果你执行idx[i],在汇编中,(idx + i * sizeof *idx) 将每次执行,而*start 已经掌握了答案。
    2. 在每次迭代中重复操作。这样,代码在保持局部性的同时,分支会更少。 gcc -O2 很可能会为您解决问题。

    【讨论】:

    • 如果你真的想手动优化那个东西到死,还有更多的工作要做。首先使用向量指令(128 位 MMX 是一个好的开始),使用指令显式地预取下一次迭代的内存,递减而不是递增(因为dec 在各种架构上设置零标志),强制对齐等
    【解决方案3】:

    我们只看到一段代码,如果你正在初始化一个全局指针数组以指向一个全局数组uint8_t,有一个更快的方法:写一个显式初始化器。初始化是在编译时完成的,在执行时几乎不需要任何时间。

    如果数组是自动的,恐怕没有更快的方法可以做到这一点。如果您的编译器很聪明并被指示使用优化(-O2、-O3 等),它可能会展开循环并生成非常有效的代码。查看汇编输出以验证这一点。如果没有,您可以自己展开循环:

    假设数组大小是4的倍数:

    for (i = 0; i < sizeof(idx) / sizeof(*idx); i += 4)
        idx[i] = idx[i+1] = idx[i+2] = idx[i+3] = &raw[0];
    

    请注意,您应该小心使用 sizeof 运算符:除了使用错误的数组进行大小计算之外,您的代码还做了 2 个隐含假设:

    • 数组元素是一个字符
    • idx 是一个数组,而不是指向数组的指针。

    建议使用sizeof(idx) / sizeof(*idx) 来计算数组元素的数量:此表达式适用于所有数组元素类型,但idx 仍需要为数组类型。定义宏:

    #define countof(a)  (sizeof(a) / sizeof(*(a)))
    

    使它更方便,但如果a 是指针,则隐藏问题。

    【讨论】:

    • 考虑到 CU 缓存的行为,可能有更有效的方法来执行此操作:以非常特定的方式交叉访问 idx 的元素可能会产生更快的代码。这是假设的,特定于 CPU 并且编写起来非常麻烦,将这种低级优化留给编译器。
    猜你喜欢
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 2013-04-19
    • 2020-03-01
    相关资源
    最近更新 更多