Lunghezza variabile Array testa in C ++?
-
30-09-2019 - |
Domanda
Guardando a questa domanda: Perché un C / C ++ necessario conoscere la dimensione di un array al momento della compilazione? è venuto in mente che gli esecutori compilatore dovrebbe hanno avuto alcune volte per ottenere i loro piedi bagnati ora (parte di essa la standard C99 , che è di 10 anni fa) e di fornire implementazioni efficienti.
Tuttavia sembra ancora (dalle risposte) per essere considerato costoso.
Questo mi sorprende in qualche modo.
Naturalmente, capisco che un offset statica è molto meglio di una dinamica uno in termini di prestazioni, e diversamente da un suggerimento non avrei effettivamente avere il compilatore eseguire un'allocazione mucchio di matrice dal momento che questo sarebbe probabilmente costato ancora di più [ questo non è stato misurato;)]
Ma io sono ancora sorpreso il presunto costo :
- se non c'è VLA in una funzione, allora non ci sarebbe alcun costo, per quanto posso vedere.
- se v'è un unico VLA, allora si può neanche metterlo prima o dopo tutte le variabili, e quindi ottenere un offset per la maggior parte dello stack frame statico (o almeno così sembra a me, ma io non sono ben versato nella gestione dello stack)
La domanda si pone di più i VLA, naturalmente, e mi chiedevo se avere uno stack VLA dedicato avrebbe funzionato. Questo mezzo di un VLA sarebbero rappresentati da un conteggio e un puntatore (di dimensioni note quindi) e la memoria effettiva presa in uno stack secondario utilizzato solo per questo scopo (e quindi veramente una pila troppo).
[riformulare]
Come i VLA sono implementati in gcc / VC ++?
è il costo davvero così impressionante?
[riformulazione fine]
Mi sembra che possa essere solo meglio di, diciamo, un vector
, anche con le implementazioni attuali, dal momento che non sostenere il costo di un'allocazione dinamica (a costo di non essere ridimensionabile).
Modifica
C'è una risposta parziale qui , tuttavia confrontando i VLA per array tradizionali sembrano ingiusto . Se conoscessimo la dimensione in anticipo, quindi non avremmo bisogno di un VLA. Nella stessa domanda AndreyT ha dato alcune indicazioni per quanto riguarda l'attuazione, ma non è preciso come vorrei.
Soluzione
Come i VLA sono implementati in gcc / VC ++?
Per quanto ne sappia VC ++ non implementa VLA. Si tratta di un compilatore C ++ e supporta solo C89 (senza VLA, non limitano). Non so come utensileria gcc VLA ma il modo più veloce possibile è quello di memorizzare il puntatore alla VLA e la dimensione in sezione statica della stack-frame. In questo modo è possibile accedere a una delle VLA con prestazioni di un array costante dimensioni (è l'ultima VLA se lo stack cresce verso il basso come in x86 (dereferenziazione [stack pointer + indice * dimensione dell'elemento + la dimensione delle ultime spinte temporanee]), e il primo VLA se cresce verso l'alto (dereferenziazione [puntatore stackframe + offset da stackframe + indice * dimensione dell'elemento])). Tutti gli altri VLA avranno bisogno ancora un'indirezione di ottenere il loro indirizzo di base dalla parte statica della pila.
[ Modifica: anche quando si utilizza il compilatore VLA può puntatore allo stack-frame-base, omettere che è ridondante altrimenti, perché tutti gli offset di puntatore di stack possono essere calcolati durante la fase di compilazione. In modo da avere un registro meno libero. - Modifica end ]
È il costo davvero così impressionante?
Non proprio. Inoltre, se non ne fanno uso, non si paga per esso.
[ Modifica: Probabilmente una risposta più corretta sarebbe: rispetto a cosa? Rispetto ad un mucchio allocato vettore, il tempo di accesso sarà lo stesso ma l'allocazione e deallocazione sarà più veloce. - Modifica end ]
Altri suggerimenti
Se dovesse essere attuato in VC ++, mi assumo la squadra compilatore avrebbe usato qualche variante del _alloca(size)
. E Credo che il costo è equivalente all'utilizzo variabili con maggiore allineamento a 8 byte in pila (come __m128
); il compilatore deve memorizzare l'originale stack pointer da qualche parte, e allineando la pila richiede un registro in più per memorizzare lo stack non allineato.
Quindi, l'overhead è fondamentalmente un riferimento indiretto in più (è necessario memorizzare l'indirizzo del VLA da qualche parte) e registrarsi pressione dovuta a memorizzare la gamma pila da qualche parte originale pure.