for循环被忽略(优化?)out

Lon*_*olf 6 c timedelay delay compiler-optimization xtensa

我使用for/while循环来实现代码中的延迟.延迟的持续时间在这里并不重要,尽管它足够大而值得注意.这是代码片段.

uint32_t i;

// Do something useful

for (i = 0; i < 50000000U; ++i)
{}

// Do something useful
Run Code Online (Sandbox Code Playgroud)

我观察到的问题是这个for循环不会被执行.它可能会被编译器忽略/优化.但是,如果我i通过volatile 限定循环计数器,则for循环似乎执行,我确实注意到执行中所需的延迟.

对于使用/不使用volatile关键字的编译器优化的理解,这种行为似乎有点违反直觉.

即使循环计数器得到优化并存储在处理器寄存器中,计数器是否仍然可以工作,也许延迟较小?(因为内存提取开销被废除了.)

我正在构建的平台是Xtensa处理器(由Tensilica提供),C编译器是由Tensilica提供的,Xtensa C/C++编译器以最高级别的优化运行.

我尝试使用gcc 4.4.7with -o3和ofast优化级别.在这种情况下,延迟似乎有效.

Eld*_*Bug 18

这完全是关于可观察的行为.你的循环的唯一可观测的行为是i50000000U在循环之后.允许编译器优化它并替换它i = 50000000U;.此i任务也将进行优化,因为其价值i没有可观察到的后果.

volatile关键字告诉编译器写入和读取i具有可观察的行为,从而阻止其优化.

编译器也不会优化对无法访问代码的函数的调用.从理论上讲,如果编译器可以访问整个操作系统代码,它可以优化除易失性变量之外的所有内容,这些变量通常放在硬件IO操作上.

这些优化规则都符合C标准中的内容(参见参考文献).

此外,如果你想要一个延迟,使用一个专门的功能(例如:OS API),它们是可靠的,不消耗CPU,不像你的旋转延迟.

  • 我认为这在N1570§5.1.2.3中有所涉及,特别是在第4段中:*在抽象机器中,所有表达式都按语义指定进行评估.实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且没有产生所需的副作用(包括由调用函数或访问volatile对象引起的任何副作用).* (5认同)
  • @LoneWolf对于裸机固件,您通常可以访问硬件计时器.延迟的一个好方法是存储定时器值,然后循环直到该值超过某个点(用定时器频率计算).您只需要一个运行计时器(或为此运行一个),它提供可靠的最小延迟. (4认同)
  • @LoneWolf在裸机固件上编写延迟循环比在某些托管桌面应用程序上更糟糕,因为在裸机系统上,您可以直接访问高精度硬件定时器.因此,使用MCU的片上定时器,它们是有原因的. (3认同)