оператор if, оценка функции и оптимизация компилятора - PullRequest
3 голосов
/ 10 июля 2020

Просто быстрый вопрос, чтобы спасти меня от тестирования (хотя я действительно должен тестировать, чтобы быть абсолютно уверенным):

Учитывая следующий C код:

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

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

Переменные r1 и r2 больше нигде в коде не используются, кроме оператора if (...). Будут ли оценены обе функции? Меня беспокоит, что компилятор может оптимизировать код, исключив r1 и r2, таким образом сделав его таким:

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

В этом случае сначала будет вычисляться fun1(), а если он возвращает FALSE, тогда fun2() не будет оцениваться не . Это не то, что я хочу, и поэтому я кодирую его, как в первом сегменте кода.

Как я могу гарантировать, что функция будет всегда быть оцененным? Я думал, что это можно сделать, назначив ее переменной, но меня беспокоит оптимизация компилятора, если он видит, что эта переменная никогда не будет использоваться позже в коде ...

Я знаю это может быть достигнуто, объявив r1 и r2 как volatile, но я хотел бы знать, есть ли более элегантное решение.

Любые комментарии по этой проблеме приветствуются, спасибо!

Редактировать: Спасибо всем, кто ответил. Я только что использовал свой первый фрагмент кода в своем проекте (это встроенная система на базе ARM Cortex-M7). Похоже, что компилятор не оптимизирует код так, как я показал выше, а оцениваются как fun1(), так и fun2() (как должны). Кроме того, компиляция кода с r1 и r2, объявленными как volatile, дает точно такой же двоичный вывод, как когда r1 и r2 являются обычными переменными (т. Е. Ключевое слово volatile не меняет вывод компилятора вообще). Это успокаивает меня, что первый фрагмент кода на самом деле является гарантированным способом оценки обеих функций перед обработкой следующего за ним оператора if (...).

Ответы [ 2 ]

5 голосов
/ 10 июля 2020

Предполагая, что код не демонстрирует неопределенного поведения, компиляторы могут выполнять только те оптимизации, которые имеют такое же внешне видимое поведение, что и неоптимизированный код.

В вашем примере два фрагмента кода выполняют две разные функции. В частности, один всегда вызывает fun2, а другой - условно. Так что вам не нужно беспокоиться о том, что первый фрагмент кода сделает что-то не так.

1 голос
/ 10 июля 2020

Вызовы не будут оптимизированы, если результат вызовов не может быть вычислен во время компиляции.

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
...