在 C 中,ARM 编译器将如何优化此结构?

In C how would an ARM compiler optimize this struct?

我有一个结构:

typedef struct mystruct_s {
    uint8_t bufferA[1024];
    uint8_t bufferB[1024];
} mystruct;

mystruct mystructA;
mystruct mystructB;

for( i = 0 ; i < 1024 ; i++ )
{
    mystructA.bufferA[i] = 0x01;
    mystructA.bufferB[i] = 0x01;
    mystructB.bufferA[i] = 0x01;
}

在我的程序中,我访问了 mystructA 中的两个缓冲区成员,但只访问了 mystructB 中的 bufferA。

如果mystructB中的成员bufferB没有被访问,编译器会优化掉它来节省内存吗?

我知道由于不同编译器的性质,这可能看起来模棱两可。

例如,如果我在 Keil 下为 STM32F4 使用 ARM C/C++ 编译器,它会做什么?

编译器无法确定是否无法访问特定内存位置,因此它必须为所有成员分配内存。

考虑这个例子*:

memcpy(&mystructB.bufferA, &mystructA.bufferA, sizeof(mystructA));

尽管在两个 struct 中只使用了 bufferA,但 bufferAbufferB 都被复制了,所以内存必须存在。


* 该示例显示了执行 mystructB = mystructA 的复杂方法。出于说明目的,我以访问 structB 的特定成员而不是 structB 本身的方式构建示例。

If member bufferB in mystructB is not accessed will the compiler optimize it out to save memory?

不,不允许编译器更改结构的内存布局。您已经告诉它保留 1024 个字节,因此它必须这样做。它不能 "partially optimize" 一个结构:它要么优化整个结构分配,要么什么都不做。

这不是模棱两可的,也不是系统相关的,所有标准编译器都必须这样做。但是,mystructB.bufferB 将包含垃圾值。


优化相关:

一般来说,"touch" RAM 内存从同一个循环中的多个位置遍布整个位置并不是一个好主意。在循环的每一圈,您都会阅读 3 个不相邻的不同区域。这可能会阻止 CPU 有效地使用数据缓存,迫使它在循环的每一圈直接写入 RAM。

即使启用了所有优化,编译器通常也不会考虑数据缓存,因为缓存内存的性质是系统特定的。

根据 MCU 数据缓存的工作方式,您实际上可以通过创建更多循环来显着提高性能:

for( i = 0 ; i < 1024 ; i++ )
    mystructA.bufferA[i] = 0x01;
for( i = 0 ; i < 1024 ; i++ )
    mystructA.bufferB[i] = 0x01;
for( i = 0 ; i < 1024 ; i++ )
    mystructB.bufferA[i] = 0x01;

现在数据以线性顺序访问,这将导致最佳缓存使用。循环的顺序很重要,它应该与分配的顺序相同。

或者,使用 memset(),因为您正在处理字节。