Изучение листинга ассемблирования, генерируемого компилятором C++ - часть 1 - Встраивание функции

ОГЛАВЛЕНИЕ

Встраивание функции

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

Инструкция встраивания, или _declspec(inline), не заставляет компилятор сделать функцию встроенной. Есть различные факторы (в основном неизвестные), определяющие, является ли функция встроенной. Это также не значит, что отсутствие директивы встраивания перед функцией не сделает ее встроенной. Листинг ассемблирования помогает выяснить, является ли функция встроенной. Берется следующий пример:

void ConvertStr(char* argv)
{
    szHelloWorld[1] = 'o';
    szHelloWorld[2] = 'l';
    szHelloWorld[3] = 'a';
    szHelloWorld[4] = '\'';
}

int main(int argc, char* argv[])
{
    printf(szHelloWorld);
    ConvertStr(szHelloWorld);
    printf(szHelloWorld);
    return 0;
}

Изучается листинг для главной функции.

_main   PROC NEAR       ; COMDAT

; 15   :    printf(szHelloWorld);

push OFFSET FLAT:?szHelloWorld@@3PADA    ; szHelloWorld
call  _printf

; 16   :   
; 17   :    ConvertStr(szHelloWorld);
; 18   :
; 19   :    printf(szHelloWorld);

push OFFSET FLAT:?szHelloWorld@@3PADA    ; szHelloWorld
mov BYTE PTR ?szHelloWorld@@3PADA+1, 111    ; 0000006fH
mov BYTE PTR ?szHelloWorld@@3PADA+2, 108    ; 0000006cH
mov BYTE PTR ?szHelloWorld@@3PADA+3, 97 ; 00000061H
mov BYTE PTR ?szHelloWorld@@3PADA+4, 39 ; 00000027H
call    _printf
add esp, 8

; 20   :
; 21   :    вернуть 0;

    xor eax, eax

; 22   : }

    ret 0

Нет команды вызова для ConvertStr, вместо этого есть много команд сдвига BYTE PTR, изменяющих символы в строке (это делает функция ConvertStr). Это показывает, что ConvertStr на самом деле была развернута как встроенная.

Отключается развертывание встроенной функции ConvertStr с помощью _declspec(noinline).

_main   PROC NEAR  ; COMDAT

; 15   :    printf(szHelloWorld);

    push    OFFSET FLAT:?szHelloWorld@@3PADA   
        ; szHelloWorld

    call    _printf

; 16   :    ConvertStr(szHelloWorld);

    push    OFFSET FLAT:?szHelloWorld@@3PADA   
        ; szHelloWorld

    call    ?ConvertStr@@YAXPAD@Z   ; ConvertStr

; 17   :    printf(szHelloWorld);

    push    OFFSET FLAT:?szHelloWorld@@3PADA           
        ; szHelloWorld

    call    _printf
    add esp, 12  ; 0000000cH

; 18   :    вернуть 0;

    xor eax, eax

; 19   : }

    ret 0
_main   ENDP

Как ожидается, есть команда вызова ConvertStr. Компилятор решает, делать ли функцию встроенной. Иногда, если встроенная функция вызывает другую встроенную функцию, встраивается только одна функция. Порой помогает использование #pragma inline_depth() и #pragma inline_recursion(). Файл листинга показывает, была ли функция встроена.