Создание * int в C ++. Какой смысл в MSVC сохранять / перезагружать возвращаемое значение функции перед ее присвоением глобальному? - PullRequest
0 голосов
/ 03 декабря 2018

Я новичок в сборке кода.При разработке на C ++ я заметил некий ассемблерный код, сгенерированный MSVC.Код, о котором идет речь:

00DA1965  push        4 // The number of bytes we want
00DA1967  call        operator new (0DA1339h) // Call to 'new' to allocate memory
00DA196C  add         esp,4 // Add the 4 bytes to the stack pointer
00DA196F  mov         dword ptr [ebp-0D4h],eax // Move the return address from EAX into a temporary variable?
00DA1975  mov         eax,dword ptr [ebp-0D4h] // Move it back into EAX?
00DA197B  mov         dword ptr [age],eax // And then into my variable?

Соответствующий код C ++:

int *age = new int;

Если я правильно понимаю, мы переместим значение в EAX во временную переменную в EBP-0D4h.И в следующей инструкции мы затем вернем его туда, где он был.

Какой смысл в этом?(00DA196F и 00DA1975)

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

MSVC разбивает строку кода:

int *age = new int;

на два этапа:

                                                ;1st step
        push        4                           ;temp var = new int
        call        operator new
        add         esp,4
        mov         dword ptr [ebp-0D4h],eax
                                                ;2nd step    
        mov         eax,dword ptr [ebp-0D4h]    ;int *age = temp var
        mov         dword ptr [age],eax
0 голосов
/ 03 декабря 2018

Анти-оптимизированный вывод asm отладочной сборки MSVC, как правило, даже более интеллектуален, чем анти-оптимизированные сборки gcc или clang.

Нет разумной причины проливать / перезагружать возвращаемое значение в стек даже вотладочная сборка : временная версия не доступна через какое-либо имя в абстрактной машине C ++, и нет никакой отладочной информации, которая позволяла бы видеть ее между концом new и обновлением p.

int* - это типично копируемый тип, поэтому при копировании возвращаемого значения в локальный тип нет конструктора копирования.Но, вероятно, именно поэтому MSVC делает это.


gcc не делает этого внутри функции или в функции статического инициализатора, если вы поместите этот new в глобальную область видимости.https://godbolt.org/z/51SM3N

Если вы не хотите смотреть на тупую асимметрию мозга, скомпилируйте с включенной оптимизацией , например -O2 или -Ox в MSVC.Затем вы получите ожидаемый статический инициализатор:

;;; x86 MSVC -O2 output
??__Ep@@YAXXZ PROC                                  ; ??__Ep@@YAXXZ, COMDAT
    push    4
    call    void * operator new(unsigned int)                            ; operator new
    add     esp, 4
    mov     DWORD PTR int * p, eax      ; p
    ret     0

или для x86-64,

?__Ep@@YAXXZ PROC                                  ; ??__Ep@@YAXXZ, COMDAT
    sub     rsp, 40                             ; 00000028H
    mov     ecx, 4
    call    void * __ptr64 operator new(unsigned __int64)                      ; operator new
    mov     QWORD PTR int * __ptr64 __ptr64 p, rax                ; p
    add     rsp, 40                             ; 00000028H
    ret     0
...