我有一个包含多个数组成员的结构:
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/