ANSI C编译器可以删除延迟循环吗?

考虑ANSI C中的while循环,其唯一目的是延迟执行:

unsigned long counter = DELAY_COUNT; while(counter--); 

我已经看到这很多用于强制执行嵌入式系统的延迟,例如。 没有sleepfunction,定时器或中断是有限的。

我对ANSI C标准的解读是,这可以通过符合标准的编译器完全删除。 它没有5.1.2.3中描述的副作用:

访问易失性对象,修改对象,修改文件或调用执行任何这些操作的函数都是副作用,这些都是执行环境状态的变化。

……并且本节还说:

实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用)。

这是否意味着可以优化循环? 即使countervolatile

笔记:

  1. 这与编译器允许消除无限循环不完全相同? ,因为它指的是无限循环,并且出现关于何时允许程序终止的问题。 在这种情况下,程序肯定会在某个时刻通过这条线,优化与否。
  2. 我知道GCC会做什么(删除-O1或更高的循环,除非countervolatile ),但我想知道标准规定了什么。

C标准符合性遵循“as-if”规则,通过该规则,编译器可以生成任何行为“好像”它在抽象机器上运行实际指令的代码。 由于不执行任何操作具有相同的可观察行为,“就像”您执行循环一样,完全允许不为其生成代码。

换句话说,在真实机器上计算的时间不是程序“可观察”行为的一部分,它只是特定实现的一种现象。

volatile变量的情况不同,因为访问volatile会将其视为“可观察”效果。

这是否意味着可以优化循环?

是。

即使反击是不稳定的?

不会。它会读取和写入一个具有可观察行为的volatile变量,因此必须发生。

如果计数器是volatile ,则编译器无法合法地优化延迟循环。 否则它可以。

像这样的延迟循环很糟糕,因为它们燃烧的时间取决于编译器如何为它们生成代码。 使用不同的优化选项可以实现不同的延迟,这几乎不是人们想要的延迟循环。

因此,这种延迟循环应该用汇编语言实现,程序员可以完全控制代码。 这通常适用于具有简单CPU的嵌入式系统。

标准规定了您看到的行为。 如果为DELAY_COUNT创建依赖关系树, DELAY_COUNT看到它具有不使用属性的修改,这意味着可以将其删除。 这是针对非易失性案例。 在易失性情况下,编译器不能使用依赖树来尝试删除此变量,因此延迟仍然存在(因为volatile意味着硬件可以更改内存映射值,或者在某些情况下意味着“我真的需要它不要抛出它离开“)如果您正在查看是否标记为volatile,它会告诉编译器,请不要将其丢弃,因为这是有原因的。