2014-10-10 10 views
7

Sto lavorando all'ottimizzazione di un progetto. Contiene una struttura di opzioni in cui l'utente può selezionare una singola opzione alla volta. Oltre all'opzione, utilizziamo anche una variabile flag per verificare quale valore di opzione è impostato per questo record. Per rendere efficiente la memoria, voglio convertire la struttura in unione. Ma come faccio a sapere quale valore variabile è impostato in unione. Perché non esiste alcuna restrizione nell'unione per recuperare un valore di una variabile anche se non è impostato.Come sapere quale valore variabile è impostato per l'unione?

struct options{ 
    int basicPay; 
    int lumsumPay; 
    int mothlyPay; 
    int weeklyPay; 
    int dailyPay; 
    int anualPay; 

    int payType; // Flag variable to check which option is selected 
}; 

union OptimizeOptions{ 
    int basicPay; 
    int lumsumPay; 
    int mothlyPay; 
    int weeklyPay; 
    int dailyPay; 
    int anualPay; 

    int payType; // Confuse at here 
}; 
+0

@ user3121023 ha ragione: l'unica volta che hai bisogno di un sindacato è quando uno o più membri hanno tipi diversi. Anche ortografia: 'lumpsumPay',' monthlyPay' e 'annualPay'. –

risposta

14

Hai provato uno union all'interno di un struct? Vediamo il seguente esempio equivalente:

union options{ 
    int basicPay; 
    int lumsumPay; 
    int mothlyPay; 
    int weeklyPay; 
    int dailyPay; 
    int anualPay; 
}; 

struct record{ 
    union options op; // Options union 
    int payType; // Flag variable to check which option is selected 
} 

L'unione (options) riserverà di memoria per la sua più grande variabile ed è possibile impostare il suo valore e la vostra struttura (record) non mancherà di tenere traccia di quel blocco di memoria unione e la bandiera payType potrebbe essere impostato un valore che indicherà al programma di recuperare la variabile perticolare dell'unione.

+12

'union options * op' non ha bisogno di essere un puntatore e renderebbe più semplice l'uso di' struct record' se fosse invece 'union options op'. – cpburnz

+0

Sì, hai ragione. – Ali

16

sindacati soffre di un problema che non esiste un modo semplice per sapere quale membro di un sindacato dell'ultima modifica. Per tenere traccia di queste informazioni, è possibile incorporare union all'interno di una struttura che ha un altro membro (chiamato "campo tag" o "discriminante"). Lo scopo del campo tag è ricordare quale membro viene modificato/aggiornato. Si può provare questo:

typedef struct{ 
     int payType;  // Tag field 

     union{ 
      int basicPay; 
      int lumsumPay; 
      int mothlyPay; 
      int weeklyPay; 
      int dailyPay; 
      int anualPay; 
     }OptimizeOptions; 

}Options; 

Ma, non c'è bisogno di scrivere sei membri separati per l'unione nel tuo caso, come tutti sono di int tipo. Di conseguenza può essere ridotto a

typedef struct{ 
    enum{BASIC_PAY, LUMSUM_PAY, MONTHLU_PAY, WEEKLY_PAY, DAILY_PAY, ANNUAL_PAY} payType; 
    int pay; 
}Options; 

Consente capire l'uso di campo tag con un semplice esempio. Supponiamo di volere un array in grado di memorizzare i dati di tipo int e double. Ciò sarebbe possibile utilizzando union. Quindi, per prima cosa definire un tipo di unione che memorizzerà int o double.

typedef union { 
     int i; 
     double d; 
} Num; 

Ora dobbiamo creare un array i cui elementi sono Num tipo

Num num_arr[100]; 

Ora, supponiamo di voler assegnare elemento 0 del num_arr per memorizzare 25, mentre l'elemento 1 negozi 3.147. Questo può essere fatto come

num_arr[0].i = 25; 
num_arr[1].d = 3.147; 

Supponiamo ora che dobbiamo scrivere una funzione che stamperà i num_arr elementi. La funzione sarebbe così:

void print_num(Num n) 
{ 
    if(n contains integer) 
     printf("%d", n.i); 
    else 
     printf("%f", n.d); 
} 

Attendere! Come potrebbe print_num decidere se n contiene un numero intero o double?

Questo sarà fatto utilizzando il campo tag:

typedef struct{ 
    enum{INT, DOUBLE} kind;  //Tag field 
    union{ 
     int i; 
     double d; 
    }u; 
}Num; 

Così, ogni volta che un valore viene assegnato a un membro di u, kindmust essere impostato sia INT o DOUBLE per ricordare che tipo abbiamo effettivamente memorizzato.Per esempio:

n.u.i = 100; 
n.kind = INT; 

La funzione print_num sarebbe stato così:

void print_num(Num n) 
{ 
    if(n.kind == INT) 
     printf("%d", n.i); 
    else 
     printf("%f", n.d); 
} 

: È responsabilità del programmatore per aggiornare il campo tag con ogni incarico al membro del union . Dimenticare di farlo porterà a bug, come indicato in comment da @ j_random_hacker.

+1

Hai dimenticato di dichiarare un _field_ di tipo 'union OptimizeOptions' - al momento stai solo dichiarando il tipo di unione stesso, ma nessun campo di quel tipo. –

+0

@HenningMakholm; Buona pesca :). Ora è fisso. – haccks

+1

Suggerisco di cambiare "can" in "must" in "' kind' sarà impostato su 'INT' o' DOUBLE' ", per chiarire che questo è qualcosa che il programmatore deve fare da sé; dimenticando di farlo causerà bug. –