C中的短路评估没有被编译器反映

Jas*_* Yu 1 c x86 gcc clang

我试图通过 GCC 和 Clang 使用 -O3 优化标志编译下面的 C 代码,在查看生成的汇编代码后,我发现这些编译器都没有实现 &&运算符的C 标准中提到的短路评估。

您可以参考下面的汇编代码了解更多信息,foo 函数的前五行代码将按顺序运行,并且它会比较 && 运算符的两个操作数,这实际上违反了标准。那么,这里面有什么误会吗?

C代码:

#include <stdio.h>
#include <stdbool.h>
void foo(int x, int y) {
  bool logical = x && y;
  printf("%d", logical);
}
int main(void) {
  foo(1, 3);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

生成的汇编代码:

foo:                                    # @foo
        test    edi, edi
        setne   al
        test    esi, esi
        setne   cl
        and     cl, al
        movzx   esi, cl
        mov     edi, offset .L.str
        xor     eax, eax
        jmp     printf                          # TAILCALL
main:                                   # @main
        push    rax
        mov     edi, offset .L.str
        mov     esi, 1
        xor     eax, eax
        call    printf
        xor     eax, eax
        pop     rcx
        ret
.L.str:
        .asciz  "%d"
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 5

首先,你的例子是错误的。

\n

给定x= 1 和y= 3,计算x && y需要计算两个操作数,因为&&仅当两个操作数都为 true 时 才为 true。

\n

其次,C 2018 5.1.2.3 6 说:

\n
\n

一致实施的最低要求是:

\n

\xe2\x80\x94 对易失性对象的访问严格按照抽象机的规则进行评估。

\n

\xe2\x80\x94 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。

\n

\xe2\x80\x94 交互设备的输入和输出动态应按照 7.21.3 的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保提示消息实际上在程序等待输入之前出现。

\n

这是程序的可观察行为。

\n
\n

这意味着编译器只负责确保上述行为按指定发生。&&当可以从左操作数推导出结果时,不需要生成不计算右||操作数的汇编语言,只要该计算不改变可观察的行为即可。编译器没有义务生成您想要的汇编语言,只是为了确保可观察的行为符合指定。

\n

当标准描述表达式是否被求值时,它是在 \xe2\x80\x9cabstract machine\xe2\x80\x9d (C 2018 5.1.2.3 1) 的上下文中描述它们,而不是描述生成的程序实际上必须做什么在汇编语言级别上进行。这个想法是,C 标准描述了程序在抽象机中生成的内容,然后编译器可以生成与抽象机中的程序具有相同可观察行为的任何程序,即使它获得完全不同的结果比抽象机中的程序更有效。

\n