Perché la memoria dello stack viene allocata quando non viene utilizzata?


14

Considera il seguente esempio:

struct vector {
    int  size() const;
    bool empty() const;
};

bool vector::empty() const
{
    return size() == 0;
}

Il codice assembly generato per vector::empty(da clang, con ottimizzazioni):

push    rax
call    vector::size() const
test    eax, eax
sete    al
pop     rcx
ret

Perché alloca lo spazio dello stack? Non è affatto usato. L' pushe poppotrebbe essere omesso. Le build ottimizzate di MSVC e gcc usano anche lo spazio dello stack per questa funzione (vedi su godbolt ), quindi ci deve essere un motivo.


7
Hai tenuto conto del thisparametro implicito ?
dan04

1
@Bob__: No. Perché dovrei? vector::size()non è definito nell'esempio per simulare che non è inline.
Dr. Gut

1
Quindi, come può un compilatore ottimizzare qualcosa che non conosce?
Bob__

1
@Bob__: Penso che conoscere l'implementazione di vector::size()non sia rilevante per allocare o non allocare un frame di stack per vector::empty(). In empty()esso è appena chiamato, qualunque cosa sia.
Dr. Gut

1
Bene, stai chiamando una funzione che restituisce qualcosa, hai bisogno di spazio per questo (se non conosci meglio).
Bob__

Risposte:


11

Alloca lo spazio dello stack, quindi lo stack è allineato a 16 byte. È necessario perché l'indirizzo di ritorno richiede 8 byte, quindi è necessario uno spazio aggiuntivo di 8 byte per mantenere allineato lo stack di 16 byte.

L'allineamento dei frame dello stack può essere configurato con argomenti della riga di comando per alcuni compilatori.

  • MSVC : la documentazione afferma che lo stack è sempre allineato a 16 byte. Nessun argomento della riga di comando può cambiarlo. L'esempio godbolt mostra che rspall'inizio della funzione vengono sottratti 40 byte , il che significa che anche qualcos'altro influisce su questo.
  • clang : l' -mstack-alignmentopzione specifica l'allineamento dello stack. Sembra che il valore predefinito sia 16, sebbene non sia documentato. Se lo si imposta su 8, l'allocazione dello stack ( pushe pop) scompare dal codice assembly generato.
  • gcc : l' -mpreferred-stack-boundaryopzione specifica l'allineamento dello stack. Se il valore dato è N, significa 2 ^ N byte di allineamento. Il valore predefinito è 4, che significa 16 byte. Se lo si imposta su 3 (ovvero 8 byte), l'allocazione dello stack ( sube addper rsp) scompare dal codice assembly generato.

Dai un'occhiata a godbolt .


Ecco perché i guru del c ++, gli esperti hanno sempre avvertito: mettere i membri di struct / class in ordine della dimensione più lunga / più grande al più piccolo ... solo in questo modo sarebbe correttamente efficiente
inoltra l'

@geza: grazie. Ho fatto delle ricerche per gli altri due compilatori e l'ho scritto sulla tua risposta. Ti piace?
Dr. Gut

1
@ Dr.Gut: grazie, hai reso la risposta molto migliore e completa. Si noti che l'allineamento dello stack è generalmente documentato nell'ABI per il sistema (ad esempio, per alcuni sistemi, ecco i documenti: github.com/hjl-tools/x86-psABI/wiki/X86-psABI ).
geza

@geza: grazie.
Dr. Gut
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.