Domanda

Nel nostro codice avevamo qualcosa del genere:

   *(controller->bigstruct) = ( struct bigstruct ){ 0 };

Questo funzionava alla grande, quindi abbiamo aggiornato le versioni di GCC e improvvisamente abbiamo iniziato a vedere gli overflow dello stack. Guardando l'assemblea, il vecchio codice GCC (2.x) stava sostanzialmente facendo questo:

memset(controller->bigstruct, 0, sizeof(struct bigstruct));

Il nuovo GCC (3.4.x) lo stava facendo

   struct bigstruct temp = { 0 };
   controller->bigstruct = temp;

Dopo aver esaminato le specifiche C99, ho capito perché; C99 richiede fondamentalmente l'esistenza di strutture anonime nello stack. È un buon concetto, ma questa struttura era larga 4 Megabyte e destinata a esistere solo su heap!

Abbiamo fatto ricorso alla nostra funzione di "inizializzazione" che imposta esplicitamente i membri, ma è brutto e un mal di testa da mantenimento. Non considero memset una soluzione adeguata, perché non posso sapere che un valore in bit di 0 è un valore zero appropriato per il tipo (nit-picking, lo so, ma eccoti; non mi dispiace che il compilatore lo fa, perché può sapere)

Qual è il modo "corretto", o almeno migliore, per inizializzare una struttura di grandi dimensioni come questa?

Per chiarire ulteriormente perché penso che memset non sia una soluzione: le regole di inizializzazione dei membri non inizializzate esplicitamente sono le stesse dell'inizializzazione statica e sono le seguenti:    - Se ha un tipo di puntatore, viene inizializzato su un puntatore nullo;    - Se ha un tipo aritmetico, viene inizializzato su zero (positivo o senza segno);    ...

'memset' imposterà la memoria a bit-pattern zero, che non è necessariamente la stessa cosa. Immagina un sistema che non utilizza numeri in virgola mobile IEEE. Insolito, ma supportato da C. La rappresentazione di 0,0 non deve significare "tutti i bit zero", potrebbe essere qualcosa di conveniente per il processore.

È stato utile?

Soluzione

memset è la strada da percorrere. Non hai molte alternative.

Fai qualcosa del tipo:

#define InitStruct(var, type) type var; memset(&var, 0, sizeof(type))

Quindi devi solo:

InitStruct(st, BigStruct);

E poi usa st come al solito ...

Non capisco come " 0 " non è valido " 0 " digitare per una struttura. L'unico modo per "inizializzare in massa" uno struct è di impostare tutta la sua memoria su un valore; altrimenti dovresti fare una logica extra per dirgli di usare un modello di bit specifico per membro. Il migliore "generico" il modello di bit da utilizzare è 0.

Inoltre - questa è la stessa logica che hai usato quando hai fatto

*(controller->bigstruct) = *( struct bigstruct ){ 0 };

Pertanto non ho la tua riluttanza a usarlo :)

Il primo commento a questo post mi ha fatto fare delle ricerche prima di chiamarlo idiota e ho trovato questo:

http://www.lysator.liu.se/ c / c-faq / c-1.html

Molto interessante; se potessi votare un commento, lo farei :)

Detto questo, l'unica opzione se si desidera scegliere come target architetture arcaiche con valori nulli diversi da 0 è ancora l'inizializzazione manuale di determinati membri.

Grazie Thomas Padron-McCarthy! Ho imparato qualcosa di nuovo oggi :)

Altri suggerimenti

Se non vuoi usare memset, puoi sempre dichiarare una copia statica della tua struttura e usare memcpy, che darà prestazioni simili. Ciò aggiungerà 4 mega al tuo programma ma probabilmente è meglio che impostare singoli elementi.

Detto questo, se GCC stesse usando memset, ed era abbastanza buono in precedenza, suggerirei che ora è abbastanza buono.

Come altri hanno già detto, memset è la strada da percorrere. Tuttavia, non utilizza memset su oggetti C ++, in particolare quelli con metodi virtuali. La sizeof (foo) includerà la tabella dei puntatori di funzioni virtuali e fare un memset su ciò causerà un grave dolore.

Se memset non risolve il problema da solo, fai semplicemente un memset e quindi inizializza tutti i membri che dovrebbero essere diversi da zero (cioè i tuoi valori in virgola mobile non IEEE).

La funzione di inizializzazione privata non è brutta piuttosto un buon modo OO per inizializzare oggetti (strutture). Presumo che la tua struttura non sia di 4 MB di puntatori, quindi suppongo che la soluzione dovrebbe essere così:

void init_big_struct(struct bigstruct *s)  
{  
    memset(s, 0, sizeof(struct bigstruct));  
    s->some_pointer = NULL; // Multiply this as needed  
}

D'altra parte il nostro codice è in esecuzione su più di 20 sistemi operativi integrati e un gran numero di hardware diversi, non incontriamo mai alcun problema con il solo memset della struttura.

hmm - prima di tutto creare una funzione init e impostare esplicitamente ogni membro È LA COSA GIUSTA - è il modo in cui funzionano i costruttori nei linguaggi OO.

e secondo: qualcuno conosce un hardware che implementa numeri in virgola mobile non IEEE? - forse Commodore 64 o qualcosa del genere ;-)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top