вызовы constexpr и встроенных функций компилируются в другую сборку с отключенной оптимизацией

#c #c 11 #assembly #inline #constexpr

#c #c 11 #сборка #встроенный #constexpr

Вопрос:

Я наткнулся на этот потрясающий онлайн-обозреватель компиляторов https://godbolt.org / который показывает ассемблерную версию вашего кода. Я также читал о новых функциях C 11 и узнал о constexpr.

взгляните на квадратную функцию ниже :

 constexpr int square(int num) {
    return num * num;
}

int main()
{
    int result = square(2);
    return 0;
}
  

и следующий код сборки, сгенерированный для двух версий (constexpr и inline)

CONSTEXPR https://godbolt.org/z/c69qrevET

 main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 4   ; compile time constant 4 = 2*2
        mov     eax, 0
        pop     rbp
        ret
  

ВСТРОЕННЫЙ https://godbolt.org/z/czaKT8fhY

 square(int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, DWORD PTR [rbp-4]
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     edi, 2
        call    square(int)
        mov     DWORD PTR [rbp-4], eax
        mov     eax, 0
        leave
        ret
  

Я везде читал, что подобные функции могут быть встроены, но почему в версии asm есть код вызова функции? Согласно встроенному определению, этого следует избегать, верно?

Ответ №1:

constexpr выполнение функций во время компиляции не гарантируется, если они не используются в контексте, где требуется постоянное выражение. Измените свой код на

 int main()
{
    constexpr int result = square(2);
    return 0;
}
  

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

Обратите внимание, что уровень оптимизации также имеет значение.

Комментарии:

1. Полезно это знать. Спасибо.

2. @Ankitsinghkushwah: если это ответ на ваш вопрос, пожалуйста, нажмите зеленую галочку, чтобы отметить его как ответ.

3. Вызов constexpr функции уже оценивается GCC во время компиляции, это «встроенная» функция, которая не является. (С отключенной оптимизацией). Кроме того, правило «как если бы» позволяет компилятору выполнять оценку во время выполнения, если он этого хочет. Только такие случаи, как int foo[square(2)]; в качестве члена структуры или в глобальной области видимости, не дадут GCC никакой возможности, даже для действительно сложной constexpr функции, которую он мог бы в противном случае (особенно при низком уровне оптимизации) вызвать во время выполнения. Итак, ключевая часть вашего ответа заключается в том, что «уровень оптимизации имеет значение».