2013-04-04 12 views
62

To pytanie pochodzi z odpowiedzi na pytanie przepełnienie stosu Why do books say, “the compiler allocates space for variables in memory”?, gdzie próbowałem pokazać OP, co dzieje się, gdy przydzielisz zmiennej na stos i jak generuje kod, który zna rozmiar pamięci do przydzielenia. Wygląda na to, że kompilator przydziela znacznie więcej miejsca niż to, co jest potrzebne.Dlaczego na stosie jest za dużo miejsca?

Jednak podczas kompilowania następujące

#include <iostream> 
using namespace std; 

int main() 
{ 
    int foo; 
    return 0; 
} 

uzyskać następujące dane wyjściowe asemblera z Visual C++ 2012 skompilowany w trybie debugowania bez optymalizacji na:

int main() 
{ 
00A31CC0 push  ebp 
00A31CC1 mov   ebp,esp 
00A31CC3 sub   esp,0CCh // Allocates 204 bytes here. 
00A31CC9 push  ebx 
00A31CCA push  esi 
00A31CCB push  edi 
00A31CCC lea   edi,[ebp-0CCh] 
00A31CD2 mov   ecx,33h 
00A31CD7 mov   eax,0CCCCCCCCh 
00A31CDC rep stos dword ptr es:[edi] 
    int foo; 
    return 0; 
00A31CDE xor   eax,eax 
} 

Dodanie jeden int do mojego programu powoduje skomentowanie linii powyżej:

00B81CC3 sub   esp,0D8h // Allocate 216 bytes 

Pytanie postawione przez @JamesKanze w mojej odpowiedzi połączonej na szczycie, to dlaczego kompilator, i najwyraźniej to nie tylko Visual C++ (nie zrobiłem eksperymentu z innym kompilatorem), przydzielone odpowiednio 204 i 216 bajtów, gdzie w pierwszym przypadku potrzebuje tylko czterech, a w drugiej potrzebuje tylko ośmiu?

Ten program tworzy 32-bitowy plik wykonywalny.

Z technicznego punktu widzenia, dlaczego konieczne może być przydzielenie 204 bajtów zamiast tylko 4?

EDIT:

Wywołanie dwie funkcje oraz tworzenie double i dwa int w głównym, można uzyskać

01374493 sub   esp,0E8h // 232 bytes 

Z tego samego programu, jak edytować powyżej, to robi to w trybie zwolnienia (bez optymalizacje):

sub esp, 8    // Two ints 
movsd QWORD PTR [esp], xmm0 // I suspect this is where my `double` goes 
+10

Ponieważ jest to tryb debugowania. – ForEveR

+2

Czy porównałeś się z nieco bardziej złożonym głównym wywoływaniem niektórych funkcji? Wiem, że g ++ po prostu alokuje wystarczającą ilość miejsca do użycia dla argumentów funkcji. nie wiem o visual C++ –

+9

Tryb debugowania może zawierać wszelkiego rodzaju strażników stosu itp. Jak zachowuje się w trybie zwolnienia? – Angew

Odpowiedz

101

Ta dodatkowa przestrzeń jest generowana przez opcję kompilacji/Zi. Który włącza Edycja + Kontynuacja. Dodatkowe miejsce jest dostępne dla zmiennych lokalnych, które możesz dodać podczas edycji kodu podczas debugowania.

Widać również efekt/RTC, inicjalizuje on wszystkie zmienne lokalne na 0xcccccccc, co ułatwia diagnozowanie problemów z powodu zapominania o inicjalizacji zmiennych. Oczywiście żaden z tych kodów nie jest generowany w domyślnych ustawieniach konfiguracji Release.

+7

Aha. Nie pomyślałem o tym. (Wiem, że niektóre kompilatory wprowadzają dodatkową przestrzeń między każdą funkcją, właśnie z tego powodu, ale nie przyszło mi do głowy, że to samo jest konieczne w przypadku zmiennych lokalnych). –

Powiązane problemy