Информация об изменениях

Сообщение Re[3]: А почему бы не сделать стек еще умнее? от 15.11.2016 11:49

Изменено 15.11.2016 11:50 Pavel Dvorkin

Здравствуйте, _smit, Вы писали:

Почти все верно


_>
_>void foo()
_>{// выделился фрейм 1 на стеке и вначале фрейма сохранился адрес программного кода куда надо возвратиться при выходе из функции,
_>   {// выделился фрейм 2 на стеке
_>      int k;
_>      int d;
_>   } // фрейм 2 освободился на стеке, k и d освободились (разрушились)

_>}// фрейм 1 освободился на стеке, str и b освободились (разрушились)
_>


В действительности по крайней мере VC++ так не делает. Память для стека отводится при входе в функцию, хотя переменные, конечно, "логически"перестают существовать при выходе на свою "}". Однако рпмять при этом не освобождается.

"Идейно" было бы правильно сделать, как отметили Вы, но в реальности делается иначе.

void f() {
    int a[100];
    for (int i = 0; i < 100; i++)
        a[i] = i;
    int x = 10;
    if (x == 10) {
        int b[100];
        for (int i = 0; i < 100; i++)
            b[i] = i;
    }
}


void f() {
00EE3C10  push        ebp  
00EE3C11  mov         ebp,esp  
00EE3C13  sub         esp,414h  // выделение памяти на все локальные переменные
00EE3C19  push        ebx  
00EE3C1A  push        esi  
00EE3C1B  push        edi  
00EE3C1C  lea         edi,[ebp-414h]  
00EE3C22  mov         ecx,105h  
00EE3C27  mov         eax,0CCCCCCCCh  
00EE3C2C  rep stos    dword ptr es:[edi]  
    int a[100];
    for (int i = 0; i < 100; i++)
00EE3C2E  mov         dword ptr [ebp-1A0h],0  
00EE3C38  jmp         f+39h (0EE3C49h)  
00EE3C3A  mov         eax,dword ptr [ebp-1A0h]  
00EE3C40  add         eax,1  
00EE3C43  mov         dword ptr [ebp-1A0h],eax  
00EE3C49  cmp         dword ptr [ebp-1A0h],64h  
00EE3C50  jge         f+57h (0EE3C67h)  
        a[i] = i;
00EE3C52  mov         eax,dword ptr [ebp-1A0h]  
00EE3C58  mov         ecx,dword ptr [ebp-1A0h]  
00EE3C5E  mov         dword ptr a[eax*4],ecx  
00EE3C65  jmp         f+2Ah (0EE3C3Ah)  
    int x = 10;
00EE3C67  mov         dword ptr [x],0Ah  
    if (x == 10) {
00EE3C71  cmp         dword ptr [x],0Ah  
00EE3C78  jne         f+0A3h (0EE3CB3h)  
        int b[100]; // а здесь ничего не выделяется
        for (int i = 0; i < 100; i++)
00EE3C7A  mov         dword ptr [ebp-350h],0  
00EE3C84  jmp         f+85h (0EE3C95h)  
00EE3C86  mov         eax,dword ptr [ebp-350h]  
00EE3C8C  add         eax,1  
00EE3C8F  mov         dword ptr [ebp-350h],eax  
00EE3C95  cmp         dword ptr [ebp-350h],64h  
00EE3C9C  jge         f+0A3h (0EE3CB3h)  
            b[i] = i;
00EE3C9E  mov         eax,dword ptr [ebp-350h]  
00EE3CA4  mov         ecx,dword ptr [ebp-350h]  
00EE3CAA  mov         dword ptr [ebp+eax*4-344h],ecx  
00EE3CB1  jmp         f+76h (0EE3C86h)  
    }
}
00EE3CB3  push        edx  
00EE3CB4  mov         ecx,ebp  
00EE3CB6  push        eax  
00EE3CB7  lea         edx,ds:[0EE3CCCh]  
00EE3CBD  call        @_RTC_CheckStackVars@8 (0EE108Ch)  
00EE3CC2  pop         eax  
00EE3CC3  pop         edx  
00EE3CC4  pop         edi  
00EE3CC5  pop         esi  
00EE3CC6  pop         ebx  
00EE3CC7  mov         esp,ebp  // а вот здесь освобождение - esp восстанавливается на значение до входа в функцию
00EE3CC9  pop         ebp  
00EE3CCA  ret


В остальном вполне согласен.
Здравствуйте, _smit, Вы писали:

Почти все верно


_>
_>void foo()
_>{// выделился фрейм 1 на стеке и вначале фрейма сохранился адрес программного кода куда надо возвратиться при выходе из функции,
_>   {// выделился фрейм 2 на стеке
_>      int k;
_>      int d;
_>   } // фрейм 2 освободился на стеке, k и d освободились (разрушились)

_>}// фрейм 1 освободился на стеке, str и b освободились (разрушились)
_>


В действительности по крайней мере VC++ так не делает. Память для стека отводится при входе в функцию, хотя переменные, конечно, "логически"перестают существовать при выходе на свою "}". Однако рпмять при этом не освобождается.

"Идейно" было бы правильно сделать, как отметили Вы, но в реальности делается иначе.

void f() {
    int a[100];
    for (int i = 0; i < 100; i++)
        a[i] = i;
    int x = 10;
    if (x == 10) {
        int b[100];
        for (int i = 0; i < 100; i++)
            b[i] = i;
    }
}


void f() {
00EE3C10  push        ebp  
00EE3C11  mov         ebp,esp  
00EE3C13  sub         esp,414h  // выделение памяти на все локальные переменные
00EE3C19  push        ebx  
00EE3C1A  push        esi  
00EE3C1B  push        edi  
00EE3C1C  lea         edi,[ebp-414h]  
00EE3C22  mov         ecx,105h  
00EE3C27  mov         eax,0CCCCCCCCh  
00EE3C2C  rep stos    dword ptr es:[edi]  
    int a[100];
    for (int i = 0; i < 100; i++)
00EE3C2E  mov         dword ptr [ebp-1A0h],0  
00EE3C38  jmp         f+39h (0EE3C49h)  
00EE3C3A  mov         eax,dword ptr [ebp-1A0h]  
00EE3C40  add         eax,1  
00EE3C43  mov         dword ptr [ebp-1A0h],eax  
00EE3C49  cmp         dword ptr [ebp-1A0h],64h  
00EE3C50  jge         f+57h (0EE3C67h)  
        a[i] = i;
00EE3C52  mov         eax,dword ptr [ebp-1A0h]  
00EE3C58  mov         ecx,dword ptr [ebp-1A0h]  
00EE3C5E  mov         dword ptr a[eax*4],ecx  
00EE3C65  jmp         f+2Ah (0EE3C3Ah)  
    int x = 10;
00EE3C67  mov         dword ptr [x],0Ah  
    if (x == 10) {
00EE3C71  cmp         dword ptr [x],0Ah  
00EE3C78  jne         f+0A3h (0EE3CB3h)  
        int b[100]; // а здесь ничего не выделяется
        for (int i = 0; i < 100; i++)
00EE3C7A  mov         dword ptr [ebp-350h],0  
00EE3C84  jmp         f+85h (0EE3C95h)  
00EE3C86  mov         eax,dword ptr [ebp-350h]  
00EE3C8C  add         eax,1  
00EE3C8F  mov         dword ptr [ebp-350h],eax  
00EE3C95  cmp         dword ptr [ebp-350h],64h  
00EE3C9C  jge         f+0A3h (0EE3CB3h)  
            b[i] = i;
00EE3C9E  mov         eax,dword ptr [ebp-350h]  
00EE3CA4  mov         ecx,dword ptr [ebp-350h]  
00EE3CAA  mov         dword ptr [ebp+eax*4-344h],ecx  
00EE3CB1  jmp         f+76h (0EE3C86h)  
    }
}
00EE3CB3  push        edx  
00EE3CB4  mov         ecx,ebp  
00EE3CB6  push        eax  
00EE3CB7  lea         edx,ds:[0EE3CCCh]  
00EE3CBD  call        @_RTC_CheckStackVars@8 (0EE108Ch)  
00EE3CC2  pop         eax  
00EE3CC3  pop         edx  
00EE3CC4  pop         edi  
00EE3CC5  pop         esi  
00EE3CC6  pop         ebx  
00EE3CC7  mov         esp,ebp  // а вот здесь освобождение - esp восстанавливается на значение до входа в функцию
00EE3CC9  pop         ebp  
00EE3CCA  ret


В остальном вполне согласен.