Rozważ następujący przykład:
struct vector {
int size() const;
bool empty() const;
};
bool vector::empty() const
{
return size() == 0;
}
Wygenerowany kod zestawu dla vector::empty
(według clang, z optymalizacjami):
push rax
call vector::size() const
test eax, eax
sete al
pop rcx
ret
Dlaczego przydziela miejsce na stosie? W ogóle nie jest używany. push
I pop
może być pominięty. Zoptymalizowane kompilacje MSVC i gcc również używają przestrzeni stosu dla tej funkcji (patrz na godbolt ), więc musi być jakiś powód.
this
parametr?vector::size()
nie jest zdefiniowany w tym przykładzie, aby zasymulować, że nie jest wstawiony.vector::size()
nie ma znaczenia dla przydzielania lub nieprzydzielania ramki stosuvector::empty()
. Wempty()
to właśnie nazywa, cokolwiek to jest.Odpowiedzi:
Przydziela przestrzeń stosu, więc stos jest wyrównany do 16 bajtów. Jest to konieczne, ponieważ adres zwrotny zajmuje 8 bajtów, więc potrzebna jest dodatkowa 8-bajtowa przestrzeń, aby utrzymać stos 16-bajtowy.
Wyrównanie ramek stosu można skonfigurować za pomocą argumentów wiersza poleceń dla niektórych kompilatorów.
rsp
początku funkcji odejmuje się 40 bajtów , co oznacza, że coś innego również na to wpływa.-mstack-alignment
Opcja określa wyrównanie stosu. Wygląda na to, że domyślnie jest to 16, choć nie zostało to udokumentowane. Jeśli ustawisz go na 8, alokacja stosu (push
ipop
) zniknie z wygenerowanego kodu zestawu.-mpreferred-stack-boundary
Opcja określa wyrównanie stosu. Jeśli podana wartość to N, oznacza to 2 ^ N bajtów wyrównania. Wartość domyślna to 4, co oznacza 16 bajtów. Jeśli ustawisz go na 3 (tj. 8 bajtów), przydział stosu (sub
iadd
dlarsp
) zniknie z wygenerowanego kodu zestawu.Sprawdź godbolt .
źródło