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

ANSI C编译器可以删除延迟循环吗?,c,optimization,standards,c89,C,Optimization,Standards,C89,考虑ANSI C中的while循环,其唯一目的是延迟执行: unsigned long counter = DELAY_COUNT; while(counter--); 我已经看到,这在嵌入式系统上被大量用于强制延迟,例如,在嵌入式系统中没有睡眠功能,并且定时器或中断是有限的 我对ANSIC标准的理解是,这可以被符合标准的编译器完全删除。它没有5.1.2.3中描述的任何副作用: 访问易失性对象、修改对象、修改文件或调用执行这些操作的函数都是副作用,即执行环境状态的更改 ……这一节还说: 如果实

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

unsigned long counter = DELAY_COUNT;
while(counter--);
我已经看到,这在嵌入式系统上被大量用于强制延迟,例如,在嵌入式系统中没有
睡眠
功能,并且定时器或中断是有限的

我对ANSIC标准的理解是,这可以被符合标准的编译器完全删除。它没有5.1.2.3中描述的任何副作用:

访问易失性对象、修改对象、修改文件或调用执行这些操作的函数都是副作用,即执行环境状态的更改

……这一节还说:

如果实际实现可以推断表达式的值没有被使用,并且没有产生所需的副作用(包括调用函数或访问易失性对象引起的副作用),则不需要计算表达式的一部分

这是否意味着可以优化循环?即使
计数器
不稳定

注:

  • 这与不完全相同,因为它指的是无限循环,并且出现了关于何时允许程序终止的问题。在这种情况下,无论优化与否,程序一定会在某个点通过这条线
  • 我知道GCC做什么(删除
    -O1
    或更高版本的循环,除非
    计数器
    易失性的
    ),但我想知道标准规定了什么
  • 这是否意味着可以优化循环

    即使计数器不稳定


    不可以。它将读取和写入具有可观察行为的易失性变量,因此它必须发生。

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

    像这样的延迟循环是不好的,因为它们燃烧的时间取决于编译器如何为它们生成代码。使用不同的优化选项可以实现不同的延迟,这很难从延迟循环中得到


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

    C标准遵从性遵循“仿佛”规则,根据该规则,编译器可以生成任何行为“仿佛”在抽象机器上运行实际指令的代码。由于不执行任何操作具有与执行循环时“仿佛”相同的可观察行为,因此完全允许不为其生成代码

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


    对于
    volatile
    变量,情况有所不同,因为访问volatile将被视为“可观察”的效果。

    标准规定了您看到的行为。如果为
    DELAY\u COUNT
    创建依赖关系树,您会看到它有一个modify-without-use属性,这意味着它可以被删除。这是指非易失性情况。在volatile情况下,编译器无法使用依赖关系树尝试删除此变量,因此延迟仍然存在(因为volatile意味着硬件可以更改内存映射值,或者在某些情况下意味着“我真的需要它,不要扔掉它”),如果标记为volatile,它会告诉编译器,请不要扔掉它,它的出现是有原因的。

    从某种意义上讲,您是否用汇编语言实现它是无关紧要的。依赖于一定次数迭代的延迟循环是不稳定的——“延迟”根据许多因素而变化,几乎所有这些因素都超出了程序员的控制范围。不要使用这样的延迟循环。@niklis不一定正确。如果CPU是一个相对哑的CPU,并且每次都使用相同数量的时钟执行指令(因为它是哑的,并且没有缓存),并且如果时钟速率不变,则延迟将非常稳定,除非中断被启用,并且ISR频繁执行并占用大量时间。在硬件初始化期间,中断通常会暂时禁用,或者直到初始化完成。如果所有这些条件都满足,那么延迟循环就没有问题了。但是因为OP明确提到了嵌入式,所以它并没有被排除在外。FTR,我当然同意这是一个糟糕的方法,但我试图确定它们是否存在更危险的问题。顺便说一句,即使在高度受控的嵌入式系统中,我也看到了这种技术的混合结果,既有优化非常有限的“哑”编译器,也有更智能的编译器。有时问题正如@NikBougalis所描述的那样——循环存在,但延迟与
    延迟\u计数
    完全不是线性的,并且可以随周围代码的变化而变化。有时情况正好相反:延迟是线性的,但最小的单位比你预期的要长得多。(我甚至不会在一个适当的多任务操作系统上尝试它-当你应该使用例如
    select
    或mutex时,甚至
    sleep
    都有点不正常。)只要可观察的行为没有改变,C标准不会禁止优化这个循环。所以标准没有特别规定。@KingsIndian:呵呵,别担心,我认为答案的多样性总是一件好事:-)