c - 扫描结构嵌套数组的有效方法

标签 c arrays for-loop performance

我有一个包含多个数组成员的结构:

typedef myData someStruct {
    uint16_t array1 [ARRAY_LENGTH]
    uint16_t array2 [ARRAY_LENGTH]
} myData;
myData testData = {0};  // Global struct

在我的程序中的某个时刻,我需要将数组设置为一组预定义值,例如,将 array1 设置为全 0,将 array2 设置为全 0xFF,等等。我的第一直觉是编写一个 for 循环,如下所示:

void someFunction (myData * test) {
    for (uint16_t i = 0; i < ARRAY_LENGTH; ++i) {
        test->array1[i] = 0xFF;
        test->array2[i] = 0xCC;
    }
}

但是我随后推断程序执行此操作所需的操作如下:

load address of array1 first position
set value 0xFF;
load far address of array2 first postion
set value 0xCC;
load far address of array1 second position
set value 0xFF;
// and so on...

然而,如果我为每个数组使用一个单独的循环,那么地址之间的距离会更近(因为数组和结构是连续存储的),所以地址每次只加载到下一个字节,从而使代码实际上更高效如下:

void someFunction (myData * test) {
    uint16_t i = 0;
    for (i; i < ARRAY_LENGTH; ++i)
        test->array1[i] = 0xFF;
    for (i = 0; i < ARRAY_LENGTH; ++i)
        test->array2[i] = 0xCC;
}

我的推理是否正确,第二个更好吗?此外,编译器(例如 gcc)通常能够自行进行这种优化吗?

最佳答案

这将取决于您的系统架构。例如,在 SPARC 系统上,缓存行大小为 64 字节,并且两个阵列都有足够的缓存槽,因此第一个版本会很高效。第一个数组元素的加载将填充缓存,后续加载将非常快。如果编译器足够聪明,它也可以使用预取。

在支持偏移寻址的 ISA 上,它实际上并不是每次都获取数组元素的地址,它只是递增一个偏移量。所以它只获取数组的基址一次,然后使用带有基址和偏移量的加载指令。每次通过循环它都会增加寄存器中的偏移量。一些指令集甚至具有自增功能。

最好的办法是编写一个示例程序/函数,然后尝试一下。这种低级别的优化需要对 CPU/系统有透彻的了解,或者需要大量的反复试验。

关于c - 扫描结构嵌套数组的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21019920/

相关文章:

c# - 试图创建一个包含结构的数组?

python - 使用 Python 生成文件创建日期和最后修改日期

c - 在 cmake 文件的 execute_process 命令中使用 cmake 变量

c - 我想要 linux 上 C 中的一个函数来收集核心转储而不终止进程

c - c中数字删除小数位的错误

arrays - 从HIVE中的给定开始日期和结束日期创建序列数组

java - 哪个在内存 : char[] or String? 方面是有效的

javascript - for循环中的html minifier解析错误

javascript - 如何设置一个按钮来执行for循环?

c - 处理位图 header