sizeof style: sizeof (tipo) o sizeof variabile?


22

Ho visto due stili di utilizzo sizeofper operazioni relative alla memoria (come in memseto malloc):

  • sizeof(type), e
  • sizeof variable o sizeof(variable)

Quale preferiresti o utilizzeresti un mix dei due stili e quando useresti ogni stile? Quali sono i pro e i contro di ogni stile e quando li usi?

Ad esempio, posso vedere la seguente coppia di situazioni in cui uno stile aiuta e l'altro no:

Quando si ottiene il riferimento indiretto del puntatore errato:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

Quando il tipo cambia:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */

Risposte:


30

I perfer sizeof(variable)sopra sizeof(type). Ritenere:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

vs.

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

Nel primo caso, è facile verificare che vengano passate le dimensioni giuste memset. Nel secondo caso, è necessario rivedere costantemente le sezioni superiore e inferiore per assicurarsi di essere coerenti.


4
Inoltre, se si modifica il tipo di variabile, il codice che presuppone il tipo dovrà cambiare. Penso che sia preferibile correggere il codice con la minor dipendenza possibile dal tipo. (Sono influenzato da un grande progetto di conversione da 16 bit a 32 bit nel corso della giornata.)
Gort the Robot,

Questo è preferibile per lavorare con array C in cui non è comune creare un typedef, ma usare cose come char array [MAX_SIZE];
mattnz,

@ vy32: 1 errato: "sizeof (array) NON restituisce le dimensioni dell'array ... dimensioni del puntatore all'array" - se si arraytratta effettivamente di un array C, sizeof(array)restituisce il numero di byte richiesti per memorizzare gli elementi dell'array . Se arrayè un puntatore al primo elemento di un array C decaduto, la tua dichiarazione è valida. Passare un array C come argomento di funzione lo fa sembrare un puntatore nella funzione - tutte le informazioni che dimostrano che era un array, come le sue dimensioni, vanno perse. Ecco perché è decaduto . Wrong 2: "le matrici in realtà non esistono in C; ... semplicemente zucchero sintattico per i puntatori."
Johann Gerell,

9

La preferenza (come sempre) è quella di riflettere la tua intenzione il più direttamente possibile.

L'intenzione è di operare contro la memoria di una variabile esistente? Se è così, allora usa sizeof(variable), poiché questo mostra il più vicino possibile che è la memoria della variabile stessa a cui tieni.

L'intenzione è di eseguire alcuni calcoli sul tipo, ad esempio per determinare quanta memoria dovrebbe essere allocata per una nuova istanza? In tal caso, utilizzare sizeof(type).

Cioè, preferisco

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

al di sopra di

bar = (struct foo *) malloc(sizeof(*bar));

poiché quest'ultimo caso sembra che tu stia tentando di accedere a una variabile che non esiste ancora.

D'altra parte, preferisco

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

al di sopra di

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

poiché l'intenzione è chiaramente di riempire zero il contenuto della variabile, quindi è la variabile contro cui dovremmo operare. Cercare di usare i metadati di tipo confonde le cose, qui.



Lo faccio sempre, ma è una questione di gusti personali. Ritengo che void *vengano automaticamente castati su altri tipi di puntatori come una cattiva funzionalità.
Aidan Cully,

3

Avrei di gran lunga preferisco sizeof(type)sopra sizeof variable. Anche se ti costringe a preoccuparsi di più sul tipo e apportare ulteriori modifiche, che consente di evitare errori puntatore indirezione, che si collocano tra la più comune causa di bug in C .

Non mi preoccuperei così tanto dei bug in cui il tipo sizeof(type)viene modificato; ogni volta che cambi il tipo di una variabile, dovresti fare una scansione veloce per vedere dove viene usata quella variabile e se devi cambiare qualche sizeof(type)istruzione. Anche se c'è sempre la possibilità di sbagliare, ha un rischio molto più basso rispetto agli errori di indiretta del puntatore.

Un vantaggio di sizeof variableè per gli array, ma in pratica ho scoperto che il passaggio di array come coppie di first / len è molto più comune (nel qual caso basta usare la lunghezza), inoltre è anche molto facile sbagliare la dimensione a causa di decadimento di array / puntatore, come in questo esempio:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}

2
"Scansione rapida per vedere dove viene utilizzata quella variabile .... c'è sempre la possibilità di sbagliare" - per me questo è il più grande pericolo di fare sizeof (tipo), motivo per cui faccio sempre sizeof (variabile). Perché il risultato finale di questo pericolo è che tutto potrebbe ancora compilarsi e, anche se si commette un errore, potrebbero essere necessari più di un anno o arresti anomali casuali e buffer corruzioni prima di rilevarlo. E non sono riuscito a stabilire la connessione (ovviamente la finestra temporale per ogni domanda è di circa 30 secondi) tra questa domanda e "errori di indiretta del puntatore".
DXM,

@DXM Con l'operando sizeof, se è un valore allora lo è sizeof var; se è un puntatore lo è sizeof *var. Questo è anche qualcosa che le persone possono sbagliare e il compilatore lo prenderà felicemente senza lamentarsi. Sostengo che questi errori sono molto più difficili da individuare e sono più comuni degli errori nel sizeof(type)modulo.
congusbongus,

1
Entrambi i tuoi diritti - i tipi C e l'operatore sizeof sono fondamentalmente rotti e non saranno mai affidabili, nulla di ciò che fai come programmatore può risolverlo.
Mattnz,

Poiché la posta è taggata C, pubblicare il codice C è più informativo del codice C ++ mat3_t::mat3_t(...).
chux - Ripristina Monica il

0

L'obiettivo è rimuovere la ridondanza. Se si utilizza sizeof per un'operazione correlata a una variabile, ovviamente si dovrà riflettere tale dimensione. Sì, puoi sbagliare come nel primo esempio, ma la cura non è usare il tipo, ma * var, abbinando correttamente l'obiettivo.

Per mitigare tali problemi è normale utilizzare macro, modelli e strumenti simili addestrati per il caso d'uso piuttosto che dimensioni nude.

Vedi la mia macro CLEAR che viene utilizzata esclusivamente al posto del memset nudo. Mi sono salvato il culo più volte in caso di refuso indiretto o quando un contenuto di una struttura ha raccolto un vettore o una stringa ...


Macro come queste sono ciò che ha dato alla programmazione Macro di C un brutto nome ......
mattnz,

@mattnz: mostra l'alternativa migliore. È molto più facile parlare di cose astratte che creare programmi realmente funzionanti
Balog Pal

1
La macro collegata è C ++ e questo post è taggato 'C' (sono lingue diverse), Ada sarebbe il mio suggerimento.
Mattnz,

@mattnz: e lo stesso argomento mostra come applicare in modo simile per C. Sembra che tu non abbia capito completamente il punto, che non è l'implementazione effettiva del contenuto ma un uso più sicuro rispetto alle cose grezze. Tra l'altro anche leggibile.
Balog Pal

0

La logica aziendale definisce la tua scelta.

  1. Se il tuo codice si riferisce a una particolare variabile e senza questa variabile il tuo codice non ha senso: scegli sizeof(var)

  2. Se il codice si occupa di un insieme di variabili con un tipo particolare, scegliere sizeof(type). Di solito questo è necessario se si dispone di una typedefche definisce molte variabili che si elaborano in modo diverso in base al loro tipo (ad esempio serializzazione). Potresti non sapere quale di queste variabili rimarrà nelle future versioni del codice, quindi scegliere il tipo come argomento è logicamente corretto. Anche la modifica di tali typedefnon influirà sulla dimensione della linea.


-1

A seconda dello scopo, la dimensione (variabile) potrebbe essere la soluzione migliore. In tal modo, è possibile modificare il tipo di variabile, se necessario, senza correggere tutte le voci per il tipo. Ma di nuovo, dipende dal tuo obiettivo.

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.