if语句,函数求值和编译器优化

3

我有一个简短的问题,想要避免测试(虽然我真的 应该 测试以确保绝对正确):

以下是一段C代码:

r1 = fun1();
r2 = fun2();

if (r1 && r2)
{
   // do something
}

在代码中,除了 if (...) 语句之外,变量 r1r2 没有被使用。这两个函数都会被执行吗?我担心编译器可能会通过消除 r1r2 来优化代码,使代码看起来像这样:

if (fun1() && fun2())
{
   // do something
}

在这种情况下,首先会评估fun1(),如果返回FALSE,则fun2()将根本不会被评估。这不是我想要的,这就是我在第一个代码段中编码的原因。
如何确保始终评估函数?我认为可以通过将其分配给变量来实现,但是如果编译器看到该变量实际上从未在代码中后面使用过,那么我会担心编译器优化......
我知道可以通过将r1r2声明为volatile来实现此目的,但我想知道是否有更优雅的解决方案。
非常感谢您对此问题的任何评论!
编辑:感谢所有回复的人。我刚刚在我的项目中使用了第一个代码片段(它是基于ARM Cortex-M7的嵌入式系统)。似乎编译器并没有像我上面所示的那样优化代码,并且fun1()fun2()都被评估(应该是这样)。此外,使用r1r2声明为volatile编译代码产生的二进制输出与将r1r2作为普通变量声明时完全相同(即volatile关键字根本不会改变编译器输出)。这使我确信,第一个代码片段实际上是在处理后跟随的if(...) 语句之前评估两个函数的保证方式。

你可能需要查看反汇编代码。 - Fiddling Bits
1
只有在编译时可以评估结果的情况下,它才会返回已优化的调用。 - 0___________
@FiddlingBits 这不会提供可靠的信息,因为即使使用相同的编译器,确切的汇编语言也可能在一瞬间发生变化。获取可靠的信息的唯一方法是在这里遵循规范。 - Konrad Rudolph
2个回答

5

假设代码没有展现出任何未定义行为,编译器只能执行与未优化代码外部可观察行为相同的优化。

在你的例子中,两段代码执行了两种不同的操作,具体来说,一种总是调用 fun2,而另一种有条件地调用它。 因此,你不需要担心第一段代码会做错事情。


1
除非调用的结果可以在编译时计算,否则这些调用不会被优化掉。
void foo()
{
    int r1 = fun1();
    int r2 = fun2();

    if (r1 && r2)
    {
        func3();
    }
}

int fun3() {return 1;}
int fun4() {func();return 0;}

void bar()
{
    int r1 = fun3();
    int r2 = fun4();

    if (r1 && r2)
    {
        func3();
    }
}

foo:
        push    {r4, lr}
        bl      fun1
        mov     r4, r0
        bl      fun2
        cmp     r4, #0
        cmpne   r0, #0
        popeq   {r4, pc}
        pop     {r4, lr}
        b       func3
fun3:
        mov     r0, #1
        bx      lr
fun4:
        push    {r4, lr}
        bl      func
        mov     r0, #0
        pop     {r4, pc}
bar:
        b       func

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接