2013-08-01 3 views
10

Una struttura con un membro di matrice flessibile, apparentemente, non è destinata a essere dichiarata, ma piuttosto utilizzata in combinazione con un puntatore a tale struttura. Quando si dichiara un membro di array flessibile, deve esserci almeno un altro membro e il membro di matrice flessibile deve essere l'ultimo membro di quella struttura.I membri di array flessibili sono davvero necessari?

Diciamo che ho uno che assomiglia a questo:

struct example{ 
    int n; 
    int flm[]; 
} 

quindi di usarlo, dovrò dichiarare un puntatore e utilizzare malloc per riservare la memoria per i contenuti della struttura.

struct example *ptr = malloc(sizeof(struct example) + 5*sizeof(int)); 

Cioè, se voglio che il mio array flm [] contenga cinque interi. Poi, posso solo usare il mio struct in questo modo:

ptr->flm[0] = 1; 

La mia domanda è, non dovrei essere in grado di utilizzare solo un puntatore invece di questo? Non solo sarebbe pre-C99 compatibile, ma potrei usarlo con o senza un puntatore a quella struttura. Considerando che devo già usare malloc con il flm, non dovrei essere in grado di farlo?

Considerare questa nuova definizione della struttura di esempio;

struct example{ 
    int n; 
    int *notflm; 
} 

struct example test = {4, malloc(sizeof(int) * 5)}; 

Mi piacerebbe anche essere in grado di utilizzare la sostituzione allo stesso modo come il membro di matrice flessibile:

Sarebbe anche questo lavoro? (Fornita la precedente definizione di esempio con notflm)

struct example test; 
test.n = 4; 
notflm = malloc(sizeof(int) * 5); 
+0

possibile duplicato di [membri di array flessibili in C - cattivo?] (Http://stackoverflow.com/questions/246977/flexible-array-members-in-c-bad). Gli array flessibili fanno parte di C99; i puntatori non sono e possono avere problemi di portabilità. –

+5

La differenza principale è che i membri di array flessibili consentono di allocare l'intera struttura in un blocco contiguo. Se vuoi copiare la struttura, calcola la sua dimensione e fai una copia. Mentre con un puntatore, devi copiare la struttura stessa, ma poi anche copiare l'array interno. –

+1

@TedHopp in che modo possibile potresti seriamente dire che i puntatori non fanno parte del C99? –

risposta

23

I puntatori non sono array. I motivi di base per scegliere quali utilizzare sono gli stessi di sempre con gli array rispetto ai puntatori. Nel caso speciale di membri di array flessibili, ecco alcuni motivi per preferirli su un puntatore:

  • Riduzione dei requisiti di archiviazione. Un puntatore ingrandirà la tua struttura di (generalmente) 4 o 8 byte, e trascorrerai molto di più in overhead se allocerai lo storage appuntito separatamente piuttosto che con una singola chiamata a malloc.

  • Migliorare l'efficienza di accesso. Un membro di array flessibile si trova a un offset costante dalla base della struttura. Un puntatore richiede un dereferenziamento separato. Ciò influisce sul numero di istruzioni richieste per accedervi e sulla pressione del registro.

  • Atomicità dell'assegnazione riuscita/insuccesso. Se si assegna la struttura e si alloca la memoria affinché punti a due passaggi separati, il codice da ripulire nei casi di errore sarà molto più brutto, poiché si ha il caso in cui uno ha avuto successo e l'altro ha avuto esito negativo. Questo può essere evitato con qualche aritmetica puntatore per ritagliarla sia dalla stessa richiesta malloc, ma è facile ottenere la logica sbagliata e invocare UB a causa di problemi di allineamento.

  • Evitare la necessità di copia profonda. Se si utilizza una matrice flessibile anziché un puntatore, è possibile semplicemente memcpy (non assegnare, poiché l'assegnazione non può conoscere la lunghezza flessibile dell'array) per copiare la struttura piuttosto che dover copiare anche i dati puntati e correggere il puntatore nella nuova copia.

  • Evitare il bisogno di profondità.È molto comodo e pulito essere in grado di aggiungere un solo oggetto a free anziché a free indirizzato anche ai dati. Questo può essere ottenuto anche con l'approccio "carving up a malloc" sopra menzionato, naturalmente, ma gli array flessibili rendono più semplice e meno soggetto a errori.

  • Sicuramente molte altre ragioni ...

+0

+1 un bel elenco di motivi, stavo cercando un bel riassunto dei benefici per questo [risposta] (http: // StackOverflow.com/a/20221073/1708801) ma non ho trovato nulla di veramente bello, ho intenzione di collegare a questa risposta e b/c questo è meglio di qualsiasi altra cosa ho trovato finora. –

0

Quei concetti non sono assolutamente necessarie, come avete sottolineato voi stessi.

Le differenze tra i due che hai dimostrato sono dove i tuoi dati si trovano in memoria.

Nel primo esempio con array flessibile i metadati e lo stesso array si trovano nello stesso blocco di memoria e possono essere spostati come un blocco (puntatore) se necessario.

Nel secondo esempio i metadati sono nello stack e l'array è altrove nell'heap. Per spostarlo/copiarlo dovrai ora spostare due blocchi di memoria e aggiornare il puntatore nella struttura dei metadati.

Generalmente gli array di dimensioni flessibili vengono utilizzati quando è necessario posizionare un array e i suoi metadati spazialmente insieme in memoria.

Un esempio in cui questo è decisamente utile è ad esempio quando si posiziona un array con i suoi metadati in un file - si ha solo un blocco continuo di memoria e ogni volta che lo si carica sarà (molto probabilmente) collocato in un altro posizione della tua VM.

+1

I dati dell'array potrebbero in molti casi essere localizzati immediatamente dopo i dati della struttura. Ciò consentirebbe l'uso di una singola allocazione, * ma * ogni volta che la struttura viene caricata, spostata o copiata, sarebbe necessario aggiornare il puntatore. – supercat