Ci sono aspetti negativi nel passare le strutture in base al valore in C, piuttosto che passare un puntatore?
Se la struttura è grande, c'è ovviamente l'aspetto performante della copia di molti dati, ma per una struttura più piccola, dovrebbe sostanzialmente essere lo stesso del passaggio di più valori a una funzione.
È forse ancora più interessante se usato come valori di ritorno. C ha solo valori di ritorno singoli dalle funzioni, ma spesso ne servono diversi. Quindi una soluzione semplice è metterli in una struttura e restituirli.
Ci sono ragioni a favore o contro questo?
Dal momento che potrebbe non essere ovvio per tutti di cosa sto parlando qui, farò un semplice esempio.
Se stai programmando in C, prima o poi inizierai a scrivere funzioni simili a queste:
void examine_data(const char *ptr, size_t len)
{
...
}
char *p = ...;
size_t l = ...;
examine_data(p, l);
Questo non è un problema. L'unico problema è che devi concordare con il tuo collega in quale ordine dovrebbero essere i parametri in modo da utilizzare la stessa convenzione in tutte le funzioni.
Ma cosa succede quando si desidera restituire lo stesso tipo di informazioni? In genere ottieni qualcosa del genere:
char *get_data(size_t *len);
{
...
*len = ...datalen...;
return ...data...;
}
size_t len;
char *p = get_data(&len);
Funziona bene, ma è molto più problematico. Un valore di ritorno è un valore di ritorno, tranne che in questa implementazione non lo è. Non c'è modo di dire da quanto sopra che la funzione get_data non è autorizzata a guardare a cosa punta len. E non c'è nulla che faccia verificare al compilatore che un valore sia effettivamente restituito tramite quel puntatore. Quindi il mese prossimo, quando qualcun altro modifica il codice senza comprenderlo correttamente (perché non ha letto la documentazione?), Si rompe senza che nessuno se ne accorga o inizia a bloccarsi in modo casuale.
Quindi, la soluzione che propongo è la semplice struttura
struct blob { char *ptr; size_t len; }
Gli esempi possono essere riscritti in questo modo:
void examine_data(const struct blob data)
{
... use data.tr and data.len ...
}
struct blob = { .ptr = ..., .len = ... };
examine_data(blob);
struct blob get_data(void);
{
...
return (struct blob){ .ptr = ...data..., .len = ...len... };
}
struct blob data = get_data();
Per qualche ragione, penso che la maggior parte delle persone farebbe istintivamente fare esaminare_data come un puntatore a un blob strutt, ma non vedo perché. Ottiene ancora un puntatore e un numero intero, è molto più chiaro che vanno insieme. E nel caso get_data è impossibile sbagliare nel modo che ho descritto prima, poiché non esiste un valore di input per la lunghezza e deve esserci una lunghezza restituita.
gettimeofday
) utilizzare invece i puntatori e le persone lo prendono come esempio.
void examine data(const struct blob)
non è corretto.