【问题标题】:In C how would an ARM compiler optimize this struct?在 C 中,ARM 编译器如何优化这个结构?
【发布时间】:2018-01-19 18:18:04
【问题描述】:

我有一个结构:

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++ 编译器,它会做什么?

【问题讨论】:

  • 用优化构建它,看看生成的代码,你会看到编译器实际上做了什么。

标签: c optimization compiler-construction arm


【解决方案1】:

如果 mystructB 中的成员 bufferB 未被访问,编译器是否会对其进行优化以节省内存?

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

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


优化相关:

一般来说,从同一个循环内的多个地方“触摸”整个地方的 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(),因为您正在处理字节。

【讨论】:

  • 我认为第一句话有点误导;只要不改变程序的可观察行为,编译器就可以优化结构大小。问题是,对于任何非平凡的程序来说,确定这种优化是否可行是非常困难的,因此编译器甚至都不会费心去尝试。
【解决方案2】:

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

考虑这个例子*

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

尽管structs 中都只使用了bufferA,但bufferAbufferB 都被复制了,因此两者的内存都必须存在。


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

【讨论】:

    猜你喜欢
    • 2012-04-11
    • 2011-10-30
    • 1970-01-01
    • 2021-09-23
    • 2010-11-15
    • 2014-02-21
    • 1970-01-01
    • 2013-09-11
    相关资源
    最近更新 更多