come assegnare più valori in una struttura in una volta?

Posso farlo sull’inizializzazione per una struttura Foo:

Foo foo = {bunch, of, things, initialized}; 

ma, non posso farlo:

 Foo foo; foo = {bunch, of, things, initialized}; 

Quindi, due domande:

  1. Perché non posso fare il secondo, il primo è un costruttore speciale solo per l’inizializzazione?
  2. Come posso fare qualcosa di simile al secondo esempio, cioè dichiarare un gruppo di variabili per una struttura in una singola riga di codice dopo che è già stato inizializzato? Sto cercando di evitare di dover fare questo per le grandi strutture con molte variabili:

     Foo foo; foo.a = 1; foo.b = 2; foo.c = 3; //... ad infinitum 

Il primo è un inizializzatore aggregato: puoi leggere su questi e gli inizializzatori contrassegnati con questa soluzione:

Cos’è la syntax di inizializzazione della struttura con tag?

È una syntax di inizializzazione speciale e non è ansible eseguire operazioni simili dopo l’inizializzazione della struttura. Quello che puoi fare è fornire una funzione membro (o non membro) per prendere la tua serie di valori come parametri che poi assegni all’interno della funzione membro – ciò ti permetterebbe di ottenere ciò dopo che la struttura è stata inizializzata in un modo che è ugualmente conciso (dopo aver scritto la funzione la prima volta, ovviamente!)

Prova questo:

 Foo foo; foo = (Foo){bunch, of, things, initialized}; 

Questo funzionerà se hai un buon compilatore (es. GCC). Potrebbe essere necessario triggersre la modalità C99 con --std=gnu99 , non sono sicuro.

In C ++ 11 puoi eseguire più assegnazioni con “tie” (dichiarato nell’intestazione tuple)

 struct foo { int a, b, c; } f; std::tie(fa, fb, fc) = std::make_tuple(1, 2, 3); 

Se la tua espressione della mano destra è di dimensioni fisse e hai solo bisogno di ottenere alcuni elementi, puoi usare il segnaposto ignora con la cravatta

 std::tie(std::ignore, fb, std::ignore) = some_tuple; // only fb modified 

Se trovi la syntax std :: tie (fa, fb, fc) anche il cluttering del codice potresti avere una funzione membro che restituisce quella tupla di riferimenti

 struct foo { int a, b, c; auto members() -> decltype(std::tie(a, b, c)) { return std::tie(a, b, c); } } f; f.members() = std::make_tuple(1, 2, 3); 

Tutto questo naturalmente considerando che sovraccaricare l’operatore di assegnazione non è un’opzione perché la tua struct non è costruibile da tale sequenza di valori, nel qual caso potresti dire

 f = foo(1, 2, 3); 

Se non ti preoccupi troppo dell’efficienza, potresti raddoppiarne l’assegnazione: ad esempio, crea una nuova istanza della struttura utilizzando l’inizializzazione aggregata, quindi copiala su:

 struct Foo foo;

 {
   struct Foo __tmp__ = {mazzo, di, cose, inizializzato};
   foo = __tmp__;
 }

Assicurati di mantenere la parte avvolta in {} s in modo da scartare la variabile temporanea non necessaria non appena non è più necessaria.

Nota che questo non è efficiente come fare, per esempio, una funzione ‘set’ nella struct (se c ++) o fuori dalla struct, accettando un puntatore struct (se C). Ma se hai bisogno di un’alternativa rapida, preferibilmente temporanea, alla scrittura di un elemento elemento per elemento, questo potrebbe succedere.

Memory Footprint – Ecco un’interessante aggiunta di i386.

Dopo molti problemi, l’utilizzo di ottimizzazione e memcpy sembra generare il minimo ingombro utilizzando i386 con GCC e C99. Sto usando -O3 qui. stdlib sembra avere tutti i tipi di ottimizzazioni del compilatore divertenti a portata di mano, e questo esempio ne fa uso (la memcpy è in realtà compilata qui).

Fai questo da:

 Foo foo; //some global variable void setStructVal (void) { const Foo FOO_ASSIGN_VAL = { //this goes into .rodata .bunch = 1, .of = 2, .things = 3, .initialized = 4 }; memcpy((void*) &FOO_ASSIGN_VAL, (void*) foo, sizeof(Foo)); return; } 

Risultato:

  • (.rodata) FOO_ASSIGN_VAL è memorizzato in .rodata
  • (.text) si verifica una sequenza di * movl FOO_ASSIGN_VAL,% registers *
  • (.text) una sequenza di registri di movl%, si verifica foo

Esempio:

  • Say Foo era una struttura a 48 campi di valori uint8_t. È allineato in memoria.

  • ( IDEALE ) Su una macchina a 32 bit, questo POTREBBE essere veloce come 12 istruzioni MOVL di immediata uscita nello spazio degli indirizzi di foo. Per me questo è 12 * 10 == 120bytes di dimensioni .text.

  • ( ATTUALE ) Tuttavia, l’utilizzo della risposta di AUTO probabilmente genererà 48 istruzioni MOVB in .text. Per me questo è 48 * 7 == 336 byte di testo. !!

  • ( PIÙ PICCOLO * ) Usa la versione di memcpy sopra. SE l’allineamento è curato,

    • FOO_ASSIGN_VAL è inserito in .rodata (48 byte),
    • 12 MOVL in% register
    • 12 MOVL outof% registers vengono utilizzati in .text (24 * 10) == 240bytes.
    • Per me quindi questo è un totale di 288 byte.

Quindi, almeno per me con il mio codice i386,

 - Ideal: 120 bytes - Direct: 336 bytes - Smallest: 288 bytes 

* Il più piccolo qui significa “l’impronta più piccola che io conosca”. Esegue anche più velocemente dei metodi precedenti (24 istruzioni vs 48). Naturalmente, la versione IDEAL è la più veloce e la più piccola, ma non riesco ancora a capirlo.

-Justin

* Qualcuno sa come ottenere l’implementazione di ‘ IDEAL ‘ sopra? Mi sta dando fastidio!

Se ti interessa l’efficienza, puoi definire un’unione della stessa lunghezza della tua struttura, con un tipo che puoi assegnare contemporaneamente.

Per assegnare valori per elementi usa la struttura della tua unione, per assegnare l’intero dato, usa l’altro tipo della tua unione.

 typedef union { struct { char a; char b; } Foo; unsigned int whole; } MyUnion; MyUnion _Union; _Union.Foo.a = 0x23; // assign by element _Union.Foo.b = 0x45; // assign by element _Union.whole = 0x6789; // assign at once 

State attenti alla vostra organizzazione della memoria (è “un” MSB o LSB di “intero”?).