2009-07-11 14 views
52

La dimensione di (enum) == sizeof (int), sempre?La dimensione di (enum) == sizeof (int), sempre?

  • O è dipendente dal compilatore?
  • È sbagliato dire che il compilatore è ottimizzato per le lunghezze delle parole (allineamento della memoria), cioè y int è la dimensione della parola su un particolare compilatore? Significa che non c'è penalità di elaborazione se uso le enumerazioni, dato che sarebbero allineate alla parola?
  • Non è meglio se inserisco tutti i codici di ritorno in una enumerazione, poiché chiaramente non mi preoccupo dei valori che ottiene, solo dei nomi mentre controllo i tipi di ritorno. Se questo è il caso, #DEFINE sarà migliore in quanto farebbe risparmiare memoria.

Qual è la prassi abituale? Se devo trasportare questi tipi di ritorno su una rete e un po 'di elaborazione deve essere eseguita all'altra estremità, quale preferiresti enumeri/# definisce/constati.

MODIFICA - Basta controllare su rete, poiché il compilatore non collega simbolicamente le macro, come fanno le persone eseguono il debug quindi, confronta il valore intero con il file di intestazione?

dalle risposte -I sono l'aggiunta di questa linea di seguito, come ho bisogno clarifications-

"Così è definito dall'implementazione, e sizeof (enum) potrebbe essere pari a sizeof (char) , cioè 1. "

  • Non significa che i controlli del compilatore per la gamma di valori in enumerazioni, e quindi assegnare la memoria. Io non la penso così, certo che non lo so. Qualcuno può spiegarmi che cosa è "potrebbe essere".
+0

Check: http://stackoverflow.com/ domande/366017/what-is-the-size-of-an-enum-in-c E questo: http://bytes.com/groups/cpp/135139-sizeof-en um-sizeof-int – Macarse

+0

Dalla rete su alcuni forum, "pensavo che un enum doveva essere piccolo quanto necessario per contenere tutti i suoi valori, in questo caso 1 byte." È vero. –

+0

Grazie a tutti sto imparando pochi dubbi ragionevoli, che penso possano sicuramente aiutare a migliorare il concetto. –

risposta

31

È dipendente dal compilatore e può variare tra le enumerazioni. Di seguito sono i semantica

enum X { A, B }; 

// A has type int 
assert(sizeof(A) == sizeof(int)); 

// some integer type. Maybe even int. This is 
// implementation defined. 
assert(sizeof(enum X) == sizeof(some_integer_type)); 

noti che "certo tipo integer" in C99 può anche includere esteso tipi interi (che l'attuazione, tuttavia, deve documentare, se li fornisce). Il tipo dell'enumerazione è un tipo che può memorizzare il valore di qualsiasi enumeratore (A e B in questo caso).

Non penso ci siano sanzioni nell'utilizzo delle enumerazioni. Gli enumeratori sono anche espressioni costanti integrali (quindi puoi usarlo per inizializzare variabili di scope statiche o di file, per esempio) e preferisco le macro quando possibile.

Gli enumeratori non necessitano di alcuna memoria di runtime. Solo quando si crea una variabile del tipo di enumerazione, è possibile utilizzare la memoria di runtime. Basti pensare agli enumeratori come costanti di tempo di compilazione.

Vorrei solo utilizzare un tipo che può memorizzare i valori dell'enumeratore (dovrei conoscere l'intervallo di valori approssimativo in precedenza), eseguire il cast e inviarlo tramite la rete. Preferibilmente, il tipo dovrebbe essere di tipo a larghezza fissa, come int32_t, quindi non entra in conflitto quando sono coinvolte diverse macchine. Oppure stamperei il numero e lo scannerò dall'altra parte, eliminando alcuni di questi problemi.


risposta a Modifica

Ebbene, il compilatore non è necessario per utilizzare qualsiasi dimensione. Una cosa facile da vedere è che il segno dei valori è importante - i tipi non firmati possono avere un notevole incremento delle prestazioni in alcuni calcoli. Quello che segue è il comportamento di GCC 4.4.0 sulla mia macchina

int main(void) { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned int" 
    unsigned int *p = &a; 
} 

Ma se si assegna un -1, poi GCC choses per usare int come il tipo che X è compatibile con

int main(void) { 
    enum X { A = -1 }; 
    enum X a; // X compatible with "int" 
    int *p = &a; 
} 

Utilizzando l'opzione --short-enums di GCC, che fa si che usi il tipo più piccolo che si adatta ancora a tutti i valori.

int main() { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned char" 
    unsigned char *p = &a; 
} 
+0

Penso che ora, invece di memorizzare ogni comando in una variabile char non firmata e lo equipaggi a un valore, lo memorizzerò in #define, come è sempre stato fatto. Enums affronterà problemi di ordine dei byte. Penso che ora capisco perché #define sono sempre stati usati per codici di errore, nomi di stati, comandi ... ecc. –

+9

Non è del tutto vero non c'è differenza tra enumerazioni e #define: come hai detto per #definisce il compilatore non vede nemmeno il token iniziale, dal momento che è sostituito con il valore reale dal preprocessore. Il compilatore tuttavia vede l'enumerazione e se si compila il codice con i simboli di debug, il debugger mostrerà le etichette enumerate invece del loro valore, il che aiuta notevolmente il debug. – Metiu

19

C99, 6.7.2.2p4 dice

Ogni tipo enumerato deve essere compatibile con char, un firmato tipo intero, o un unsigned tipo intero. La scelta del tipo è definita dall'implementazione, 108) ma deve essere in grado di rappresentare i valori di tutti i membri dell'enumerazione . [...]

nota 108 aggiunge

Un'implementazione può ritardare la scelta di quale numero intero tipo finché è stata vista tutte le costanti di enumerazione.

quindi è definito dall'implementazione, e sizeof (enum) potrebbe essere uguale a sizeof (char), cioè 1.

Nello scegliere le dimensioni di alcuni piccola gamma di numeri interi, c'è sempre una penalità. Se lo fai piccolo in memoria, probabilmente c'è una penalità di elaborazione; se lo fai più grande, c'è una penalità di spazio. È un compromesso spazio-temporale.

I codici di errore sono in genere #defines, perché devono essere estensibili: diverse librerie possono aggiungere nuovi codici di errore.Non puoi farlo con le enumerazioni.

+0

Ciò non significa che il compilatore controlla l'intervallo di valori nell'enumerazione e quindi assegna la memoria. Io non la penso così, naturalmente non lo so :). Alcuni possono mostrare per favore cosa è "potrebbe essere" –

+0

"Il compilatore fa" è un'affermazione inutile. Ci sono molti compilatori nel mondo, e alcuni lo fanno in un modo, e altri lo fanno in un modo diverso (anche sullo stesso hardware). Se vuoi sapere cosa fa un compilatore specifico, devi nominare il compilatore (compresa la versione e la CPU di destinazione e il sistema operativo). Potrebbe benissimo essere che * il tuo * compilatore usa sempre int per enumerare. –

+0

La seconda risposta [qui] (http://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c) fornisce una versione diversa dello stesso standard dove lo dice deve essere compatibile con 'int'. La sua versione è obsoleta (si collega a una bozza) o è la tua? – Norswap

13

È il sizeof (enum) == sizeof (int), sempre

Lo standard ANSI C dice:

Ogni tipo enumerato deve essere compatibile con char, un tipo intero con segno o un tipo intero senza segno. La scelta del tipo è definita dall'implementazione. (6.7.2.2 Enumerationspecifiers)

Quindi direi che significa no.

Se questo è il caso, #DEFINE sarà migliore in quanto farebbe risparmiare memoria.

In che modo l'utilizzo definisce la memoria di salvataggio utilizzando un enum?Un enum è solo un tipo che ti consente di fornire maggiori informazioni al compilatore. Nell'eseguibile risultante effettivo, è appena convertito in un numero intero, proprio come il preprocessore converte una macro creata con #define nel suo valore.

Qual è la prassi abituale. I se devo trasportare questi tipi di ritorno su una rete e qualche elaborazione deve essere eseguita dall'altra parte

Se si prevede di trasferire valori su una rete e elaborarli dall'altra parte, è necessario definire un protocollo. Decidi la dimensione in bit di ciascun tipo, l'endianess (in cui sono ordinati i byte) e assicurati di rispettarlo sia nel codice client sia nel codice server. Inoltre, non dare per scontato che, dato che funziona, hai capito bene. Potrebbe semplicemente accadere che l'endianess, ad esempio, corrisponda alle coppie di piattaforme client e server scelte, ma potrebbe non essere sempre così.

+0

sì, questo è il problema, ho trasferito un certo valore per essere usato come comando sulla rete, e vorrei rendere il più efficiente e robusto possibile, cioè ho bisogno di pareri su cosa usare per il comando #define o enumerazioni, la gamma di i comandi non devono essere più di 20 comandi, quindi in base a tutti nel limite char. Penso che lo posterò come una nuova domanda Avrei una risposta migliore. –

+1

La cosa più semplice da fare sarebbe semplicemente utilizzare un carattere non firmato. Non devi preoccuparti dell'endianess o della codifica in questo modo. – IRBMe

+0

forse potresti aggiungere un riferimento a [Devo usare cstdint?] (Https://stackoverflow.com/q/6144682/2932052) per la sezione di rete – Wolf

3

Su alcuni compilatori le dimensioni di un enumerazione dipendono dal numero di voci nell'Enum. (meno di 255 entrate => byte, più di 255 entrate int) Ma questo dipende dal compilatore e dalle impostazioni del compilatore.

+0

c'è comunque posso forzarlo. Un bel input, però. –

+0

A causa di questi problemi nel nostro progetto (dobbiamo usare un compilatore C davvero vecchio) abbiamo deciso di non usare enum. Ma per definire tutto con #define – nuriaion

4

No.

Esempio: The CodeSourcery compiler

Quando si definisce un enum come questo:

enum MyEnum1 { 
A=1, 
B=2, 
C=3 
}; 
// will have the sizeof 1 (fits in a char) 

enum MyEnum1 { 
A=1, 
B=2, 
C=3, 
D=400 
}; 
// will have the sizeof 2 (doesn't fit in a char) 

Details dalla loro mailing list

+0

se questo è il caso è fantastico. –

+3

non è vero .... dipende dall'implementazione .... entrambi i codici danno l'output come 4 sul mio sistema.Platform - Ubuntu 10.04 (32-bit), compilatore gcc –

+0

Non un cattivo esempio, ma entrambi i link http: // www.codesourcery.com/sgpp (1 °) e http://www.codesourcery.com/archives/arm-gnu/msg02684.html (2 °) sono rotti. (sperando in un aggiornamento di riparazione.) – Wolf

Problemi correlati