Domanda

Sto usando BOOST_PP per fare calcoli di precompilazione del preprocessore. Mi sto concentrando su un'applicazione in cui la dimensione del codice è estremamente importante per me. (Quindi, per favore non dire il compilatore dovrebbe o di solito lo fa, ho bisogno di controllare ciò che viene eseguita in fase di compilazione e ciò che il codice viene generato). Tuttavia, voglio essere in grado di utilizzare lo stesso nome della funzione / macro sia per i costanti intere e variabili. Come esempio banale, posso avere

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

Questo non fa quello che io voglio che, valutando a

int a = 10;

durante la fase di compilazione.

Tuttavia, voglio anche che sia usato a

int b = 5;
int a = TWICE(b);

Questo dovrebbe essere pre-elaborato per

int b = 5;
int a = 5 * 2;

Naturalmente, posso farlo utilizzando le macro tradizionali come

#define TWICE(n) n * 2

Ma poi si pretende molto fare quello che voglio fare per costanti intere (la loro valutazione in fase di compilazione).

Quindi, la mia domanda è: esiste un trucco per verificare se l'argomento è un letterale o una variabile, e quindi utilizzare definizioni diverse. vale a dire, qualcosa di simile:

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

modifica: Così che cosa sono davvero dopo è un modo per verificare se qualcosa è una costante disposizione in fase di compilazione, e quindi un buon argomento per le funzioni BOOST_PP_. Mi rendo conto che questo è diverso da quello che la maggior parte delle persone si aspettano da un preprocessore e raccomandazioni generali di programmazione. Ma non c'è sbagliato modo di programmazione, quindi per favore non odio sulla questione se non siete d'accordo con la sua filosofia. C'è una ragione esiste la biblioteca BOOST_PP, e questa domanda è con lo stesso spirito. Si potrebbe semplicemente non essere possibile però.

È stato utile?

Soluzione

Si sta cercando di fare qualcosa che è meglio lasciare alle ottimizzazioni del compilatore.

int main (void) {
  int b = 5;
  int a = b * 2;

  return a; // return it so we use a and it's not optimized away
}

gcc -O3 -s t.c

 .file "t.c"
 .text
 .p2align 4,,15
.globl main
 .type main, @function
main:
.LFB0:
 .cfi_startproc
 movl $10, %eax
 ret
 .cfi_endproc
.LFE0:
 .size main, .-main
 .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
 .section .note.GNU-stack,"",@progbits

L'ottimizzazione compilatore di ottimizzare.

EDIT: Sono consapevole del fatto che non si vuole sentire che il compilatore "dovrebbe" o "di solito" lo fa. Tuttavia, ciò che si sta cercando di fare non è qualcosa che è destinato a essere fatto nel preprocessore C; le persone che hanno progettato il linguaggio C e il preprocessore C progettato per lavorare con la pre-elaborazione token come si dell'atomo di base. Il CPP è, per molti versi, "stupido". Questa non è una brutta cosa (in realtà, questo è in molti casi, ciò che lo rende così utile), ma alla fine della giornata, è un preprocessore. Si preprocessa file di origine prima di essere analizzati. Si preprocessa file di origine prima che si verifichi l'analisi semantica. Si preprocessa file di origine prima che la validità di un dato file sorgente sia selezionata. Capisco che non si vuole sentire che questo è qualcosa che il parser e analizzatore semantico devono gestire o di solito lo fa. Tuttavia, questa è la realtà della situazione. Se si vuole progettare il codice che è incredibilmente piccolo, allora si dovrebbe fare affidamento sul vostro compilatore per farlo di lavoro invece di cercare di creare costrutti preprocessore per fare il lavoro. Pensate in questo modo: migliaia di ore di lavoro è andato in vostro compilatore, quindi cercate di riutilizzare come gran parte di quel lavoro possibile

Altri suggerimenti

Non approccio molto diretto, però:

struct operation {
    template<int N>
    struct compile {
        static const int value = N;
    };
    static int runtime(int N) { return N; }
};

operation::compile<5>::value;
operation::runtime(5);

alternativamente

operation<5>();
operation(5);

Non v'è alcuna reale possibilità di mescolare i due livelli (preprocessore e valutazione di variabili ). Da quello che ho capito da te domanda, b dovrebbe essere una costante simbolica?

Credo che si dovrebbe utilizzare il tradizionale

#define TWICE(n) ((n) * 2)

, ma poi, invece di inizializzazione delle variabili con le espressioni, li si dovrebbe inizializzare con costanti di tempo di compilazione. L'unica cosa che vedo per forzare la valutazione in fase di compilazione e di avere costanti simboliche in C sono costanti di enumerazione integrali. Questi sono definiti per avere tipo int e sono valutati al momento della compilazione.

enum { bInit = 5 };
int b = bInit;
enum { aInit = TWICE(bInit) };
int a = aInit; 

E, in generale, non dovrebbe essere troppo parsimoniosi con const (come per il vostro b) e controllare l'assemblatore prodotto con -S.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top