"Const statica" vs "#define" vs "enum"


585

Quale è meglio usare tra le seguenti affermazioni in C?

static const int var = 5;

o

#define var 5

o

enum { var = 5 };

35
È interessante notare che questa è quasi esattamente la stessa domanda di stackoverflow.com/questions/1637332/static-const-vs-define . L'unica differenza è che quella domanda riguarda il C ++ e questa riguarda il C. Dato che la mia risposta era specifica per il C ++, dico che non li rende identici, ma altri potrebbero non essere d'accordo.
TED

53
Non identico, sicuramente. Esistono molte aree in cui C ++ consente la sintassi C per motivi di compatibilità. In questi casi, domande come "qual è il modo migliore per fare X" avranno risposte diverse in C ++. Ad esempio inizializzazione dell'oggetto.
MSalters,


In che modo non si basa sull'opinione? Ognuno di essi ha uno scopo diverso
Sam Hammamy,

1
@RobertSsupportsMonicaCellio, Sì. Grazie per l'intimità
Vijay

Risposte:


690

Dipende da cosa ti serve il valore. Tu (e tutti gli altri finora) hai omesso la terza alternativa:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

Ignorando i problemi relativi alla scelta del nome, quindi:

  • Se è necessario passare un puntatore in giro, è necessario utilizzare (1).
  • Poiché (2) è apparentemente un'opzione, non è necessario passare i puntatori in giro.
  • Sia (1) che (3) hanno un simbolo nella tabella dei simboli del debugger, che semplifica il debug. È più probabile che (2) non abbia un simbolo, lasciandoti a chiederti di cosa si tratta.
  • (1) non può essere utilizzato come dimensione per array di portata globale; entrambi (2) e (3) possono.
  • (1) non può essere utilizzato come dimensione per array statici nell'ambito della funzione; entrambi (2) e (3) possono.
  • Sotto C99, tutti questi possono essere utilizzati per array locali. Tecnicamente, l'uso di (1) implicherebbe l'uso di un VLA (array di lunghezza variabile), sebbene la dimensione a cui fa riferimento 'var' sarebbe ovviamente fissata alla dimensione 5.
  • (1) non può essere utilizzato in luoghi come le istruzioni switch; entrambi (2) e (3) possono.
  • (1) non può essere utilizzato per inizializzare le variabili statiche; entrambi (2) e (3) possono.
  • (2) può modificare il codice che non si desidera modificare perché viene utilizzato dal preprocessore; entrambi (1) e (3) non avranno effetti collaterali inaspettati come quello.
  • È possibile rilevare se (2) è stato impostato nel preprocessore; né (1) né (3) lo consentono.

Quindi, nella maggior parte dei contesti, preferisce l '"enum" rispetto alle alternative. Altrimenti, è probabile che il primo e l'ultimo punto elenco siano i fattori di controllo - e devi pensare di più se devi soddisfare entrambi contemporaneamente.

Se chiedessi informazioni su C ++, useresti sempre l'opzione (1) - la const statica.


111
lista fantastica! Uno svantaggio enumè che sono implementati come int([C99] 6.7.2.2/3). A #defineconsente di specificare unsigned, long with Ue Lsuffixes e constconsente di specificare un tipo. enumpuò causare problemi con le normali conversioni di tipo.
Gauthier

37
(2) le persone si lamentano SEMPRE della sicurezza del tipo. Non capisco mai perché non usi semplicemente "#define var ((int) 5)" e evviva hai ottenuto la sicurezza del tipo con una definizione.
Ingo Blackman,

6
@RedX: dovresti essere in un ambiente molto particolare per lo spazio di una preoccupazione. Detto questo, enum#defineutilizza spazio extra, di per sé. Il valore verrà visualizzato nel codice oggetto come parte delle istruzioni anziché essere allocato nella memoria nel segmento di dati o nell'heap o nello stack. Avrai dello spazio assegnato per il static const int, ma il compilatore potrebbe ottimizzarlo se non prendi un indirizzo.
Jonathan Leffler,

15
Un altro 'voto' per enums (e static const): non possono essere cambiati. a definepuò essere #undefine'd dove an enume static constsono fissi sul valore dato.
Daan Timmer,

15
@QED: No, grazie. Una semplice costante è sicura tra parentesi. Oppure, mostrami come un programma che potrebbe essere legittimamente previsto per la compilazione verrebbe modificato non avendo il 5 tra parentesi. Se fosse l'argomento di una macro in stile funzione o se ci fossero operatori nell'espressione, allora avresti ragione a biasimarmi se non avessi incluso le parentesi. Ma questo non è il caso qui.
Jonathan Leffler il

282

Parlando in generale:

static const

Perché rispetta l'ambito ed è sicuro per i tipi.

L'unica avvertenza che ho potuto vedere: se si desidera che la variabile possa essere definita sulla riga di comando. C'è ancora un'alternativa:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

Quando possibile, anziché macro / puntini di sospensione, utilizzare un'alternativa sicura per tipo.

Se hai davvero BISOGNO di andare con una macro (ad esempio, vuoi __FILE__o __LINE__), allora faresti meglio a nominare la tua macro MOLTO attentamente: nella sua convenzione di denominazione Boost raccomanda tutte le lettere maiuscole, a partire dal nome del progetto (qui BOOST_ ), mentre sfogli la libreria noterai che questo è (generalmente) seguito dal nome della particolare area (libreria), quindi con un nome significativo.

In genere crea nomi lunghi :)


2
D'accordo - anche con #define c'è un pericolo generale di codice mangling in quanto il preprocessore non è a conoscenza della sintassi.
NeilDurant,

10
È meglio usare #if di #ifdef, ma per il resto sono d'accordo. +1.
Tim Post

58
Questo è l'evangelismo C ++ standard. La risposta che segue è MOLTO più chiara nello spiegare quali sono le opzioni e cosa significano davvero. In particolare: ho appena avuto un problema con "const statica". Qualcuno l'ha usato per definire circa 2000 "costanti" in un file di intestazione. Quindi questo file di intestazione è stato incluso in circa 100 file ".c" e ".cpp". => 8 MB per "cons". Grande. Sì, so che potresti usare un linker per rimuovere i consulti senza riferimenti, ma questo ti lascia comunque quali sono i "cons" a cui si fa riferimento. A corto di spazio cosa c'è che non va in questa risposta.
Ingo Blackman,

2
@IngoBlackman: con un buon compilatore, staticdovrebbero rimanere solo quelli il cui indirizzo è preso; e se l'indirizzo è stato preso uno non avrebbe potuto usare un #defineo enum(nessun indirizzo) ... quindi non riesco davvero a vedere quale alternativa avrebbe potuto essere usato. Se riesci a eliminare la "valutazione del tempo di compilazione", potresti invece cercarla extern const.
Matthieu M.

15
@Tim Post: #ifpotrebbe essere preferibile rispetto #ifdefai flag booleani, ma in questo caso renderebbe impossibile definire varcome 0dalla riga di comando. Quindi, in questo caso, #ifdefha più senso, purché 0sia un valore legale per var.
Maarten,

108

In C, in particolare? In C la risposta corretta è: usare #define(o, se appropriato, enum)

Mentre è utile avere le proprietà di scoping e typing di un constoggetto, in realtà gli constoggetti in C (in contrapposizione a C ++) non sono costanti vere e quindi sono generalmente inutili nella maggior parte dei casi pratici.

Quindi, in C la scelta dovrebbe essere determinata da come pensi di usare la tua costante. Ad esempio, non è possibile utilizzare un const intoggetto come caseetichetta (mentre una macro funzionerà). Non è possibile utilizzare un const intoggetto come larghezza del campo bit (mentre una macro funzionerà). In C89 / 90 non è possibile utilizzare un constoggetto per specificare una dimensione dell'array (mentre una macro funzionerà). Anche in C99 non è possibile utilizzare un constoggetto per specificare una dimensione dell'array quando è necessario un array non VLA .

Se questo è importante per te, determinerà la tua scelta. Il più delle volte, non avrai altra scelta che usare #definein C. E non dimenticare un'altra alternativa, che produce vere costanti in C - enum.

In C ++ gli constoggetti sono costanti vere, quindi in C ++ è quasi sempre meglio preferire la constvariante (non c'è bisogno di esplicito staticin C ++).


6
"non puoi usare un oggetto const int come etichetta case (mentre una macro funzionerà)" ---> Riguardo a questa affermazione ho testato una variabile const int in C nel caso in cui funzioni ....
john

8
@john: Bene, devi fornire il codice che hai testato e nominare il compilatore specifico. L'uso di const intoggetti nelle etichette dei casi è illegale in tutte le versioni del linguaggio C. (Ovviamente, il tuo compilatore è libero di supportarlo come estensione non standard del linguaggio C ++.)
AnT

11
"... e quindi di solito sono inutili nella maggior parte dei casi pratici ." Non sono d'accordo. Sono perfettamente utili fintanto che non è necessario utilizzare il nome come espressione costante. La parola "costante" in C significa qualcosa che può essere valutato in fase di compilazione; constsignifica sola lettura. const int r = rand();è perfettamente legale.
Keith Thompson,

In c ++, è meglio usare constexprrispetto a constspecialmente con i stlcontenitori come arrayo bitset.
Mayukh Sarkar,

1
@john devi aver testato in una switch()dichiarazione, non in caseuna. Anch'io sono stato catturato da questo ☺
Hi-Angel,

32

La differenza tra static conste #defineè che il primo utilizza la memoria e il successivo non utilizza la memoria per l'archiviazione. In secondo luogo, non è possibile passare l'indirizzo di un #definementre è possibile passare l'indirizzo di un static const. In realtà dipende dalle circostanze in cui ci troviamo, dobbiamo selezionarne una tra queste due. Entrambi sono al meglio in circostanze diverse. Per favore, non dare per scontato che uno sia migliore dell'altro ... :-)

Se così fosse, Dennis Ritchie avrebbe tenuto da solo il migliore ... hahaha ... :-)


6
+1 per menzionare la memoria, alcuni sistemi integrati non hanno ancora molto, anche se probabilmente inizierei usando i costi statici e cambierei solo in #define se necessario.
fluffyben

3
L'ho appena provato. Infatti, const int utilizza memoria aggiuntiva rispetto a #define o enum. Poiché programmiamo sistemi integrati, non possiamo permetterci l'utilizzo di memoria aggiuntiva. Quindi, torneremo a usare #define o enum.
Davide Andrea

2
In pratica non è più (più) vero che a constusi la memoria. GCC (testato con 4.5.3 e alcune versioni più recenti) ottimizza facilmente il valore const intletterale diretto nel codice quando si utilizza -O3. Pertanto, se si esegue uno sviluppo integrato con RAM ridotta (ad es. AVR), è possibile utilizzare in modo sicuro i costi C se si utilizza GCC o un altro compilatore compatibile. Non l'ho provato ma mi aspetto che Clang faccia la stessa cosa tra l'altro.
Raffaello,

19

In C #defineè molto più popolare. Ad esempio, è possibile utilizzare questi valori per dichiarare le dimensioni dell'array:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C non ti consente di utilizzare static consts in questo contesto per quanto ne so. In C ++ dovresti evitare le macro in questi casi. Tu puoi scrivere

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

e addirittura tralasciamo staticperché il collegamento interno è constgià implicito [solo in C ++].


1
Cosa intendi con "collegamento interno"? Posso avere const int MY_CONSTANT = 5;in un file e accedervi con extern const int MY_CONSTANT;in un altro. Non sono riuscito a trovare alcuna informazione nello standard (almeno C99) sulla constmodifica del comportamento predefinito "6.2.2: 5 Se la dichiarazione di un identificatore per un oggetto ha un ambito file e nessuno speci fi catore di classe di archiviazione, il suo collegamento è esterno".
Gauthier,

@Gauthier: Mi dispiace, per quello. Avrei dovuto dire "è implicito da const già nel linguaggio C ++". Questo è specifico per C ++.
sellibitze,

@sellibitze è bello vedere alcuni argomenti lungo la strada invece di tonnellate di PARERE Se ci fosse un bonus per argomenti veri, ce l'hai!
Paul,

1
A partire da C99, il tuo secondo frammento è legale. barè un VLA (array di lunghezza variabile); è probabile che il compilatore generi codice come se la sua lunghezza fosse costante.
Keith Thompson,

14

Un altro svantaggio di constin C è che non è possibile utilizzare il valore per inizializzare un altro const.

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

Anche questo non funziona con una const poiché il compilatore non la vede come una costante:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

Sarei felice di usare dattiloscritto constin questi casi, altrimenti ...


5
Un po 'in ritardo al gioco, ma questa domanda è emersa in un'altra domanda. Inseguire il motivo per cui static uint8_t const ARRAY_SIZE = 16;all'improvviso non si compila più può essere un po 'impegnativo, in particolare quando #define ARRAY_SIZE 256sono sepolti dieci strati in profondità in una trama intricata di intestazioni. Che il nome di tutti i tappi ARRAY_SIZErichiede problemi. Prenota ALL_CAPS per le macro e non definisci mai una macro che non è nel modulo ALL_CAPS.
David Hammen,

@ David: un buon consiglio, che seguirò.
Gauthier,

1
4 anni dopo mi hai risparmiato un sacco di tempo a capire perché non potevo "nidificare" const. Questo potrebbe essere più votato!
Plouff,

11

Se riesci a cavartela, static constha molti vantaggi. Obbedisce ai normali principi dell'ambito, è visibile in un debugger e generalmente obbedisce alle regole alle quali le variabili obbediscono.

Tuttavia, almeno nello standard C originale, in realtà non è una costante. Se lo usi #define var 5, puoi scrivere int foo[var];come una dichiarazione, ma non puoi farlo (tranne che come estensione del compilatore "con static const int var = 5;. Questo non è il caso in C ++, dove la static constversione può essere usata ovunque la #defineversione possa, e credo che questo è anche il caso di C99.

Tuttavia, non nominare mai una #definecostante con un nome minuscolo. Sostituirà qualsiasi possibile uso di quel nome fino alla fine dell'unità di traduzione. Le costanti macro devono trovarsi in quello che è effettivamente il loro spazio dei nomi, che è tradizionalmente tutte le lettere maiuscole, forse con un prefisso.


6
Sfortunatamente, questo non è il caso di C99. constin C99 non è ancora una vera costante. È possibile dichiarare la dimensione dell'array con a constin C99, ma solo perché C99 supporta array a lunghezza variabile. Per questo motivo, funzionerà solo dove sono consentiti i VLA. Ad esempio, anche in C99, non è ancora possibile utilizzare a constper dichiarare la dimensione di un array di membri in a struct.
AnT

Sebbene sia corretto che C99 non ti permetta di farlo, GCC (testato con 4.5.3) ti permetterà di inizializzare perfettamente le matrici con una const intdimensione come se fosse una const C ++ o una macro. Indipendentemente dal fatto che tu voglia dipendere da questa deviazione di GCC dallo standard, è una tua scelta, personalmente lo farei a meno che tu non possa davvero rinunciare a usare un altro compilatore di GCC o Clang, quest'ultimo ha la stessa funzionalità qui (testato con Clang 3.7).
Raffaello,

7

È SEMPRE preferibile usare const, invece di #define. Questo perché const viene trattata dal compilatore e #define dal preprocessore. È come se #define non facesse parte del codice (in termini approssimativi).

Esempio:

#define PI 3.1416

Il nome simbolico PI non può mai essere visto dai compilatori; può essere rimosso dal preprocessore prima che il codice sorgente arrivi anche a un compilatore. Di conseguenza, il nome PI potrebbe non essere inserito nella tabella dei simboli. Questo può essere fonte di confusione se durante la compilazione viene visualizzato un errore che comporta l'uso della costante, poiché il messaggio di errore può fare riferimento a 3.1416, non a PI. Se il PI fosse definito in un file di intestazione che non hai scritto, non avresti idea da dove provenisse quel 3.1416.

Questo problema può anche insorgere in un debugger simbolico, perché, di nuovo, il nome con cui stai programmando potrebbe non essere nella tabella dei simboli.

Soluzione:

const double PI = 3.1416; //or static const...

6

#define var 5ti causerà problemi se hai cose del genere mystruct.var.

Per esempio,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

Il preprocessore lo sostituirà e il codice non verrà compilato. Per questo motivo, lo stile di codifica tradizionale suggerisce che tutte le costanti #defineusano lettere maiuscole per evitare conflitti.


6

Ho scritto un programma di test rapido per dimostrare una differenza:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

Questo compila con questi errori e avvertenze:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

Si noti che enum genera un errore quando define dà un avviso.


4

La definizione

const int const_value = 5;

non definisce sempre un valore costante. Alcuni compilatori (ad esempio tcc 0.9.26 ) allocano solo la memoria identificata con il nome "const_value". Utilizzando l'identificatore "const_value" non è possibile modificare questa memoria. Ma potresti comunque modificare la memoria usando un altro identificatore:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

Questo significa la definizione

#define CONST_VALUE 5

è l'unico modo per definire un valore costante che non può essere modificato in alcun modo.


8
La modifica di un valore costante mediante un puntatore è un comportamento indefinito. Se sei disposto ad andare lì, #definepuò anche essere modificato, modificando il codice macchina.
ugoren,

In parte hai ragione. Ho testato il codice con Visual Studio 2012 e viene stampato 5. Ma non si può modificare #defineperché è una macro preprocessore. Non esiste nel programma binario. Se si voleva modificare tutti i luoghi in cui CONST_VALUEveniva utilizzato, si doveva farlo uno per uno.
user2229691

3
@ugoren: Supponiamo che tu scriva #define CONST 5, quindi if (CONST == 5) { do_this(); } else { do_that(); }, e il compilatore elimini il elseramo. Come proponete di modificare il codice macchina per passare CONSTa 6?
Keith Thompson,

@KeithThompson, non ho mai detto che può essere fatto facilmente e in modo affidabile. Solo che #definenon è a prova di proiettile.
ugoren,

3
@ugoren: Il mio punto è che "modificare il codice macchina" non è un modo sensato per duplicare l'effetto della modifica del valore di a #define. L'unico vero modo per farlo è modificare il codice sorgente e ricompilare.
Keith Thompson,

4

Sebbene la domanda riguardasse numeri interi, vale la pena notare che #define ed enum sono inutili se hai bisogno di una struttura o stringa costante. Entrambi vengono in genere passati a funzioni come puntatori. (Con le stringhe è richiesto; con le strutture è molto più efficiente.)

Per quanto riguarda gli interi, se ti trovi in ​​un ambiente incorporato con una memoria molto limitata, potresti doverti preoccupare di dove è memorizzata la costante e di come vengono compilati gli accessi ad essa. Il compilatore potrebbe aggiungere due contro in fase di esecuzione, ma aggiungere due #define in fase di compilazione. Una costante #define può essere convertita in una o più istruzioni MOV [immediate], il che significa che la costante è effettivamente memorizzata nella memoria del programma. Una costante const verrà memorizzata nella sezione .const nella memoria dati. Nei sistemi con architettura Harvard, potrebbero esserci differenze nelle prestazioni e nell'utilizzo della memoria, anche se probabilmente sarebbero piccole. Possono essere importanti per l'ottimizzazione del core degli anelli interni.


3

Non pensare che ci sia una risposta per "che è sempre la cosa migliore" ma, come ha detto Matthieu

static const

è sicuro. Il mio più grande problema con gli animali domestici #define, tuttavia, è quando il debug in Visual Studio non è possibile guardare la variabile. Dà un errore che il simbolo non può essere trovato.


1
"non puoi guardare la variabile" Esatto, non è una variabile. Non cambia, perché devi guardarlo? Puoi trovare ovunque sia usato semplicemente cercando l'etichetta. Perché dovresti (o addirittura vuoi) guardare un #define?
Marshall Eubanks,

3

Per inciso, un'alternativa a #define, che fornisce l'ambito corretto ma si comporta come una costante "reale", è "enum". Per esempio:

enum {number_ten = 10;}

In molti casi, è utile definire tipi enumerati e creare variabili di tali tipi; in tal caso, i debugger potrebbero essere in grado di visualizzare le variabili in base al nome dell'enumerazione.

Un avvertimento importante nel farlo, tuttavia: in C ++, i tipi enumerati hanno una compatibilità limitata con numeri interi. Ad esempio, per impostazione predefinita, non è possibile eseguire l'aritmetica su di essi. Trovo che sia un curioso comportamento predefinito per gli enum; mentre sarebbe stato bello avere un tipo "enum rigoroso", dato il desiderio di avere C ++ generalmente compatibile con C, penso che il comportamento predefinito di un tipo "enum" dovrebbe essere intercambiabile con numeri interi.


1
In C, le costanti di enumerazione sono sempre di tipo int, quindi "enum hack" non può essere usato con altri tipi di numeri interi. (Il tipo di enumerazione è compatibile con un tipo intero definito dall'implementazione, non necessariamente int, ma in questo caso il tipo è anonimo quindi non ha importanza.)
Keith Thompson,

@KeithThompson: da quando ho scritto quanto sopra, ho letto che MISRA-C squawk se un compilatore assegna un tipo diverso da intuna variabile tipizzata da enumerazione (che i compilatori sono autorizzati a fare) e si tenta di assegnare a tale variabile un membro della propria enumerazione. Vorrei che i comitati standard aggiungessero modi portatili per dichiarare i tipi interi con la semantica specificata. QUALSIASI piattaforma, indipendentemente dalle chardimensioni, dovrebbe essere in grado di dichiarare, ad esempio, un tipo che avvolgerà la mod 65536, anche se il compilatore deve aggiungere molte AND R0,#0xFFFFistruzioni equivalenti.
supercat,

Puoi usare uint16_t, anche se ovviamente non è un tipo di enumerazione. Sarebbe bello consentire all'utente di specificare il tipo intero utilizzato per rappresentare un determinato tipo di enumerazione, ma è possibile ottenere quasi lo stesso effetto con un typedeffor uint16_te una serie di #defines per i singoli valori.
Keith Thompson,

1
@KeithThompson: Capisco che per ragioni storiche, siamo bloccati dal fatto che alcune piattaforme valuteranno 2U < -1Lcome vere e altre come false, e ora siamo bloccati dal fatto che alcune piattaforme implementeranno un confronto tra uint32_te int32_tcome firmato e alcuni come non firmati, ma ciò non significa che il Comitato non sia stato in grado di definire un successore verso l'alto compatibile con C che includa tipi la cui semantica sarebbe coerente su tutti i compilatori.
supercat,

1

Una semplice differenza:

Al momento della pre-elaborazione, la costante viene sostituita con il suo valore. Quindi non è possibile applicare l'operatore di dereference a una definizione, ma è possibile applicare l'operatore di dereference a una variabile.

Come si suppone, definire è più veloce della const statica.

Ad esempio, avendo:

#define mymax 100

non puoi fare printf("address of constant is %p",&mymax);.

Ma avendo

const int mymax_var=100

puoi fare printf("address of constant is %p",&mymax_var);.

Per essere più chiari, la definizione viene sostituita dal suo valore nella fase di pre-elaborazione, quindi non abbiamo alcuna variabile memorizzata nel programma. Abbiamo solo il codice dal segmento di testo del programma in cui è stato utilizzato il parametro di definizione.

Tuttavia, per const statici abbiamo una variabile che è allocata da qualche parte. Per gcc, const statici sono allocati nel segmento di testo del programma.

Sopra, volevo parlare dell'operatore di riferimento, quindi sostituisci la dereferenza con il riferimento.


1
La tua risposta è molto sbagliata Si tratta di C, la tua risposta si riferisce a C ++, che ha una semantica molto diversa per il constqualificatore. C non ha costanti simboliche diverse dalle enum-costanti . A const intè una variabile. Confondi anche il linguaggio e le implementazioni specifiche. Non è richiesto dove posizionare l'oggetto. E non è nemmeno vero per gcc: in genere inserisce constvariabili qualificate nella .rodatasezione. Ma ciò dipende dalla piattaforma di destinazione. E intendi l'indirizzo dell'operatore &.
troppo onesto per questo sito il

0

Abbiamo esaminato il codice assemblatore prodotto sull'MBF16X ... Entrambe le varianti danno lo stesso codice per le operazioni aritmetiche (ad esempio ADD Immediate).

Quindi const intè preferito per il controllo del tipo mentre #defineè vecchio stile. Forse è specifico del compilatore. Quindi controlla il tuo codice assemblatore prodotto.


-1

Non sono sicuro di avere ragione, ma secondo me chiamare il #definevalore d è molto più veloce che chiamare qualsiasi altra variabile (o valore const) normalmente dichiarata. È perché quando il programma è in esecuzione e deve usare alcune variabili normalmente dichiarate, deve saltare al posto esatto in memoria per ottenere quella variabile.

Al contrario, quando usa il #definevalore d, il programma non ha bisogno di saltare a nessuna memoria allocata, prende semplicemente il valore. Se #define myValue 7e il programma chiama myValue, si comporta esattamente come quando chiama 7.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.