2013-06-15 13 views
28

Sono confuso su quando utilizzare macro o enumerazioni. Entrambi possono essere usati come costanti, ma qual è la differenza tra loro e qual è il vantaggio di uno dei due? È in qualche modo collegato al livello del compilatore o no?Cosa rende una costante migliore in C, una macro o un enum?

+2

Penso che questa sia una grande domanda quando la si considera in questo modo: Quali sono le differenze tra l'utilizzo di macro e enumerazioni per definire le costanti in C? –

+0

Francamente, questo dovrebbe essere chiuso come un duplicato di ["stat const" vs "#define" vs "enum" in C] (https://stackoverflow.com/questions/1674032/). –

risposta

25

In termini di leggibilità, le enumerazioni apportano costanti migliori rispetto alle macro, poiché i valori correlati sono raggruppati. Inoltre, enum definisce un nuovo tipo, quindi i lettori del tuo programma avranno più tempo a capire cosa può essere passato al parametro corrispondente.

Confronta

#define UNKNOWN 0 
#define SUNDAY 1 
#define MONDAY 2 
#define TUESDAY 3 
... 
#define SATURDAY 7 

a

typedef enum { 
    UNKNOWN 
, SUNDAY 
, MONDAY 
, TUESDAY 
, ... 
, SATURDAY 
} Weekday; 

È molto più facile da leggere il codice come questo

void calendar_set_weekday(Weekday wd); 

di questo

void calendar_set_weekday(int wd); 

perché si conoscono le costanti che è possibile passare.

+4

Infatti, ma si potrebbe ugualmente attenersi ai macro e quindi 'typedef int Weekday;' poiché né typedef né enumer sono typesafe (in questo senso) in C ... –

+1

Per me, le macro sono in realtà una scelta migliore per il debug. So immediatamente quale costante simbolica corrisponde a un valore numerico senza dover contare tutti i suoi precedenti membri enum. –

+8

@ H2CO3: In 'gdb', io uso' p (int) Thursday', o 'p (Weekday) 3'. – jxh

17

Una macro è una cosa del preprocessore e il codice compilato non ha idea degli identificatori creati. Sono già stati sostituiti dal preprocessore prima che il codice colpisca il compilatore. Un enum è un'entità di tempo di compilazione e il codice compilato conserva informazioni complete sul simbolo, che è disponibile nel debugger (e in altri strumenti).

Preferire le enumerazioni (quando possibile).

+0

Penso che enum sia più comodo rispetto alla macro in caso di debug. –

+2

Non discutendo, ma con 'gcc -g3', puoi compilare un eseguibile gdb-friendly che conserva informazioni sulle macro. –

1

In pratica, c'è poca differenza. Sono ugualmente utilizzabili come costanti nei tuoi programmi. Alcuni potrebbero preferire l'uno o l'altro per ragioni stilistiche, ma non riesco a pensare ad alcun motivo tecnico per preferire l'uno rispetto all'altro.

Una differenza è che le macro consentono di controllare il tipo integrale di costanti correlate. Ma un enum utilizzerà uno int.

#define X 100L 
enum { Y = 100L }; 

printf("%ld\n", X); 
printf("%d\n", Y); /* Y has int type */ 
+0

In C, le costanti 'enum' sono sempre' int', non esiste una regola di questo tipo su tipi più ampi. Potresti mescolare le cose con C++? –

+0

@JensGustedt: Ah, catturato da un'altra estensione GCC. Risolto, grazie. – jxh

8

Nota ci sono alcune differenze tra macro e enumerazioni, e una di queste proprietà possono renderli (ONU) adatto come una particolare costante.

  • enumerazione (compatibile con int). In qualsiasi contesto in cui è richiesto un tipo non firmato (si pensi soprattutto alle operazioni bit a bit!), Le enumerazioni sono fuori.
  • se long long è più largo di int, le costanti grandi non rientrano in un enum.
  • La dimensione di un enum è sizeof(int). Per matrici di piccoli valori (fino al CHAR_MAX) è possibile che si desideri un char foo[] anziché un array enum foo[].
  • enumerazioni sono numeri interi. Non puoi avere enum funny_number { PI=3.14, E=2.71 }.
  • le enumerazioni sono una funzionalità C89; K & I compilatori R (certamente antico) non li capiscono.
+0

+1. E le enumerazioni non possono essere usate in condizioni di pre-elaborazione. –

+2

In realtà, la dimensione delle enumerazioni è [* not * guaranteed] (http://stackoverflow.com/a/366033/440302) per essere uguale a 'int' sebbene la maggior parte dei compilatori in pratica usino' int' per la compatibilità binaria motivi. – Rufflewind

+0

+1. Le persone usano enum per dichiarare le costanti troppo spesso. – Ivan

3

Se la macro è implementata correttamente (i.e non ha problemi di associatività quando viene sostituito), quindi non c'è molta differenza nell'applicabilità tra le costanti macro ed enum nelle situazioni in cui sono applicabili , ovvero nella situazione in cui sono necessarie specifiche costanti di interi con segno.

Tuttavia, in generale le macro offrono funzionalità molto più flessibili. Enum impone un tipo specifico alle tue costanti: avranno il tipo int (o, possibilmente, un tipo di intero con segno più grande) e saranno sempre firmati. Con le macro è possibile utilizzare la sintassi costante, i suffissi e/o le conversioni di tipo esplicito per produrre una costante di qualsiasi tipo.

Le enumerazioni funzionano meglio quando si dispone di un gruppo di costanti intere sequenziali strettamente associate. Funzionano particolarmente bene quando non ti interessa affatto i valori effettivi delle costanti, cioè quando ti interessi solo se hanno dei valori unici ben educati. In tutti gli altri casi le macro sono una scelta migliore (o fondamentalmente l'unica scelta).

7

In C, è meglio utilizzare le enumerazioni per le enumerazioni effettive: quando alcune variabili possono contenere uno di più valori a cui è possibile assegnare nomi. Un vantaggio dell'enumerazione è che il compilatore può eseguire alcuni controlli oltre a quanto richiesto dalla lingua, come se una dichiarazione di switch sul tipo enum non mancasse in uno dei casi. Gli identificatori enum si propagano anche nelle informazioni di debug. In un debugger, è possibile vedere il nome dell'identificatore come il valore di una variabile enum, anziché solo il valore numerico.

Le enumerazioni possono essere utilizzate solo per l'effetto collaterale della creazione di costanti simboliche di tipo integrale. Ad esempio:

enum { buffer_size = 4096 }; /* we don't care about the type */ 

questa pratica non è così diffusa. Per prima cosa, buffer_size verrà utilizzato come numero intero e non come tipo enumerato. Un debugger non renderà 4096 in buffer_size, perché quel valore non sarà rappresentato come il tipo enumerato. Se dichiari alcuni char array[max_buffer_size]; allora sizeof array non verrà visualizzato come buffer_size. In questa situazione, la costante di enumerazione scompare al momento della compilazione, quindi potrebbe anche essere una macro. E ci sono degli svantaggi, come non essere in grado di controllare il suo tipo esatto. (Potrebbe esserci qualche piccolo vantaggio in alcune situazioni in cui l'output delle fasi di pre-elaborazione della traduzione viene acquisito come testo. Una macro sarà convertita in 4096, mentre buffer_size rimarrà come buffer_size).

Un simbolo del preprocessore ci permette di fare questo:

#define buffer_size 0L /* buffer_size is a long int */ 

Si noti che i vari valori da C di <limits.h> come UINT_MAX sono simboli del preprocessore e non simboli enum, con buone ragioni per questo, in quanto tali identificatori bisogno di avere una precisione determinato tipo. Un altro vantaggio di un simbolo del preprocessore è che siamo in grado di testare per la sua presenza, o addirittura prendere decisioni in base al suo valore:

costanti
#if ULONG_MAX > UINT_MAX 
/* unsigned long is wider than unsigned int */ 
#endif 

Naturalmente possiamo testare enumerati anche, ma non in modo tale che possiamo cambiare dichiarazioni globali basate sul risultato.

Enumerations sono inoltre poco adatto per bitmasks:

enum modem_control { mc_dsr = 0x1, mc_dtr = 0x2, mc_rts = 0x4, ... } 

semplicemente non ha senso, perché quando i valori sono combinati con un OR bit a bit, producono un valore al di fuori del tipo. Tale codice causa anche un mal di testa, se è mai stato trasferito su C++, che ha (un po 'più) enumerazioni di tipo sicuro.

+0

Possiamo cambiare il valore di enum in fase di compilazione e const è uguale a enum o macro –

Problemi correlati