使指针数组中的所有指针指向 C 中的同一事物?
Make all pointers in an array of pointers point to the same thing in C?
我有这两个定义:
uint8_t *idx[0x100];
uint8_t raw[0x1000];
除了遍历 idx
的每个元素以将它们全部指向 raw[0]
之外,还有其他方法吗?
for (i=0; i<sizeof(raw); i++)
idx[i] = &raw[0];
一定有比↑那个更快的方法。是否有等同于 memset
的指针?
简单直接的循环可能是最好的方法(请注意,正如其他人指出的那样,您当前的循环中存在错误)。
优点是这类循环很容易优化,这是编译器非常擅长的常见情况,您的编译器将根据需要使用向量指令和其他优化来保持它非常快无需手动优化自己。
当然,与手动优化相比,它更易读、更可维护。
当然如果有特殊情况,比如你想用空指针填充它,或者你知道编译时的内容是什么,那么有一些稍微更有效的方法可以做到这一点,但在一般情况下,让编译器轻松优化代码是获得良好性能的最简单方法。
我们只看到了一段代码,如果你正在初始化一个全局指针数组指向一个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
是指针,则隐藏问题。
从性能工程的角度来看,确实有办法让它比
更快
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;
速度更快主要有两个原因:
- 直接操作指针。如果你做
idx[i]
,在汇编中,每次都会执行(idx + i * sizeof *idx)
,而*start
已经有了答案。
- 每次迭代重复操作。这样,代码将在保持局部性的同时减少分支。
gcc -O2
很可能会为您解决问题。
我有这两个定义:
uint8_t *idx[0x100];
uint8_t raw[0x1000];
除了遍历 idx
的每个元素以将它们全部指向 raw[0]
之外,还有其他方法吗?
for (i=0; i<sizeof(raw); i++)
idx[i] = &raw[0];
一定有比↑那个更快的方法。是否有等同于 memset
的指针?
简单直接的循环可能是最好的方法(请注意,正如其他人指出的那样,您当前的循环中存在错误)。
优点是这类循环很容易优化,这是编译器非常擅长的常见情况,您的编译器将根据需要使用向量指令和其他优化来保持它非常快无需手动优化自己。 当然,与手动优化相比,它更易读、更可维护。
当然如果有特殊情况,比如你想用空指针填充它,或者你知道编译时的内容是什么,那么有一些稍微更有效的方法可以做到这一点,但在一般情况下,让编译器轻松优化代码是获得良好性能的最简单方法。
我们只看到了一段代码,如果你正在初始化一个全局指针数组指向一个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
是指针,则隐藏问题。
从性能工程的角度来看,确实有办法让它比
更快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;
速度更快主要有两个原因:
- 直接操作指针。如果你做
idx[i]
,在汇编中,每次都会执行(idx + i * sizeof *idx)
,而*start
已经有了答案。 - 每次迭代重复操作。这样,代码将在保持局部性的同时减少分支。
gcc -O2
很可能会为您解决问题。