2011-01-22 21 views
27

Alla fine dell'articolo qui: http://www.learncpp.com/cpp-tutorial/45-enumerated-types/, si menziona il seguente:C++ - enum vs. const vs #define

Infine, come variabili costanti, tipi enumerati compaiono nel debugger, making sono più utili dei # valori definiti a questo proposito.

Come si ottiene la frase in grassetto qui sopra?

Grazie.

+0

ho modificato il titolo e ha aggiunto un tag, spero che non mi dispiacerebbe. :-) – Nawaz

+0

@Nawaz. Va benissimo, non ti preoccupare. – Simplicity

+0

possibile duplicato di ["const statico" vs "#define" in c] (http://stackoverflow.com/questions/1674032/static-const-vs-define-in-c) –

risposta

28

Considerate questo codice,

#define WIDTH 300 

enum econst 
{ 
    eWidth=300 
}; 

const int Width=300; 

struct sample{}; 

int main() 
{ 
     sample s; 
     int x = eWidth * s; //error 1 
     int y = WIDTH * s; //error 2 
     int z = Width * s; //error 3 
     return 0; 
} 

Ovviamente ciascuno risultati moltiplicazione in compilation-errore, ma vedere come il GCC genera i messaggi per ogni errore moltiplicazione:

prog.cpp:19: error: no match for ‘operator*’ in ‘eWidth * s’
prog.cpp:20: error: no match for ‘operator*’ in ‘300 * s’
prog.cpp:21: error: no match for ‘operator*’ in ‘Width * s’

Nel messaggio di errore , non vedi la macro WIDTH che hai #defined, giusto? Questo perché quando GCC fa un tentativo di compilare la riga corrisponde al secondo errore, non vede WIDTH, vede solo 300, come prima che GCC compili la riga, il preprocessore ha già sostituito con WIDTH con 300. Acceso D'altra parte, non vi è alcuna cosa del genere accade con enumeWidth e constWidth.

vedere l'errore voi stessi qui: http://www.ideone.com/naZ3P


Inoltre, leggere Item 2 : Prefer consts, enums, and inlines to #defines da Effective C++ da Scott Meyers.

+1

Certo, Clang probabilmente produrrebbe un messaggio di errore migliore mostrando la linea che ha causato l'errore e quindi include la macro (insieme alla sua espansione). Anche se sono d'accordo sul fatto che le macro non dovrebbero essere usate per le costanti, penso che un trattamento migliore della domanda non userebbe i messaggi di errore di gcc come la pietra angolare del ragionamento. –

+0

@MatthieuM .: Clang potrebbe produrre un messaggio di errore migliore, ma quelli che usano GCC per compilare il loro codice non stanno ricompilando il loro codice con Clang in modo da vedere un messaggio di errore migliore. {contd} – Nawaz

+0

{contd} ... Quindi tale ragionamento è molto dipendente dal compilatore, e quindi penso che prendere il messaggio di errore di Clang come la pietra angolare del ragionamento non sarebbe neanche meglio, perché qualcuno potrebbe venire a dire esattamente ciò che ha detto, sostituendo * "Clang" * con * "GCC, MSVC" * e * "better" * con * "not-so-better" *, concludendo il suo comnent con * "Penso che un trattamento migliore della domanda non usa i messaggi di errore di ** Clang ** come la pietra angolare del ragionamento "*. Spero tu abbia capito il mio punto. :-) – Nawaz

0

Almeno per Visual Studio 2008 che attualmente ho a disposizione, questa frase è corretta. Se si dispone di

#define X 3 
enum MyEnum 
{ 
    MyX = 3 
}; 

int main(int argc, char* argv[]) 
{ 
    int i = X; 
    int j = (int)MyX; 
    return 0; 
} 

e si imposta un breakpont in main, è possibile posizionare il mouse sopra "MyX" e vedere che restituisce 3. Non si vede nulla di utile se si passa sopra X.

Ma questa non è una proprietà del linguaggio, ma piuttosto un comportamento IDE. Le prossime versioni potrebbero farlo in modo diverso, così come altri IDE. Quindi basta controllare per il tuo IDE per vedere se questa frase si applica nel tuo caso.

+2

It ** is ** a proprietà linguistiche, in quanto 'X' non è nemmeno visto dal compilatore (solo il valore preelaborato' 3'), quindi il debugger non ha assolutamente alcun modo di utilizzare 'X' come nome simbolico, quindi mostrerà solo la parola chiave valore '3'. Questo è vero per tutti i compilatori e gli IDE. OTOH che mostra simboli come 'MyX' nel debugger è in effetti una caratteristica specifica per l'IDE, ma è così comune che dubito che esista un IDE moderno che non offre questo. –

6

#define i valori sono sostituiti dal pre-processore con il valore con cui sono dichiarati, quindi nel debugger, vede solo il valore, non il nome # definito, ad es. se hai #define NUMBER_OF_CATS 10, nel debugger vedrai solo 10 (poiché il pre-processore ha sostituito ogni istanza di NUMBER_OF_CATS nel tuo codice con 10.

Un tipo enumerato è un tipo in sé e i valori sono istanze costanti di questo tipo, quindi il pre-processore lascia da solo e vedrai la descrizione simbolica del valore nel debugger

3

Il compilatore memorizza le informazioni enum nel file binario quando il programma viene compilato con determinati opzioni

Quando una variabile è di tipo enum, un debugger può mostrare il nome dell'enumerazione, come mostrato meglio con un esempio:

enum E { 
    ONE_E = 1, 
}; 

int main(void) 
{ 
    enum E e = 1; 

    return 0; 
} 

Se si compila che con gcc -g è possibile provare quanto segue in gdb:

Reading symbols from test...done. 
(gdb) b main 
Breakpoint 1 at 0x804839a: file test.c, line 8. 
(gdb) run 
Starting program: test 

Breakpoint 1, main() at test.c:7 
7    enum E e = 1; 
(gdb) next 
9    return 0; 
(gdb) print e 
$1 = ONE_E 
(gdb) 

Se è stato utilizzato un definiscono, non si avrebbe un tipo corretto di dare e, e avrebbe dovuto usare un numero intero In tal caso, il compilatore stamperebbe 1 anziché ONE_E.

Il flag -g chiede a gdb di aggiungere informazioni di debug al binario. Si può anche vedere che è lì con l'emissione di:

xxd test | grep ONE_E 

non credo che questo funzionerà in tutte le architetture, però.

+0

Grazie per la risposta. Cosa intendi con: "Il compilatore memorizza le informazioni enum nel file binario"? Grazie. – Simplicity

+0

Letteralmente, il file binario contiene quell'informazione in un formato che gdb comprende. Dal manuale di gcc: -g Produce informazioni di debug nel formato nativo del sistema operativo (...).GDB può funzionare con queste informazioni di debug. – Penz

0

sto rispondendo troppo tardi, ma mi sento di poter aggiungere qualcosa - enum vs. const vs # define

enum -

  1. Non richiede valori assining (se vuole solo avere valori sequenziali 0, 1, 2 ..), Mentre in caso di # definisce il necessario per gestire manualmente i valori che potrebbero causare un errore umano a volte
  2. Funziona altrettanto variabile durante il debug on-line il valore della enum può essere guardato in finestra di controllo
  3. Si può avere una variabile di tipo enum a cui è possibile assegnare un enum

    numeri typedef enum { DFAULT, CASE_TRUE, CASE_OTHER, };

    int main (void) { numero numeri = CASE_TRUE; }

const -

  1. E 'costante memorizzato in sola lettura area di memoria, ma è possibile accedere utilizzando l'indirizzo che non è possibile in caso di #define
    1. Hai digita check in mano se usi const anziché #define
  2. definisce direttiva di pre-elaborazione ma const è tempo di compilazione per esempio

    const char * name = "vikas";

È possibile accedere al nome e utilizzare il suo indirizzo di base per leggere il come Vikas [3] per leggere 'a' ecc

#defines - sono direttive del preprocessore muti che fa testuale sostituzione

10

enum è una costante di tempo di compilazione con informazioni di debug senza allocazione di memoria.

const viene assegnato con una memoria, a seconda che sia ottimizzato via dal compilatore con propagazione costante.

#define non dispone di spazio di archiviazione.

+2

La migliore risposta concisa. – tprk77

+0

'enum' prenderebbe spazio di archiviazione ogni volta che una variabile di quel tipo' enum' è dichiarata nel programma. Non è vero? Credo che la tua menzione riguardo 'enum' sia per il caso in cui una variabile di quel tipo' enum' non viene mai dichiarata nel programma. Ma perché qualcuno dovrebbe dichiarare un enum e non usarlo? – RBT