2015-01-22 19 views
5

Sto pensando al seguente problema: Voglio programmare un microcontrollore (diciamo un tipo mega AVR) con un programma che utilizza una sorta di tabelle di ricerca.Come rendere GCC valutare le funzioni in fase di compilazione?

Il primo tentativo sarebbe quello di individuare la tabella in un file separato e crearla utilizzando qualsiasi altro linguaggio di scripting/programma/.... In questo caso c'è un po 'di sforzo per creare i file di origine necessari per C.

Il mio pensiero era ora di utilizzare il preprocessore e il compilatore per gestire le cose. Ho cercato di realizzare questo con una tabella di valori del seno (solo come esempio):

#include <avr/io.h> 
#include <math.h> 

#define S1(i,n) ((uint8_t) sin(M_PI*(i)/n*255)) 
#define S4(i,n) S1(i,n), S1(i+1,n), S1(i+2,n), S1(i+3,n) 

uint8_t lut[] = {S4(0,4)}; 

void main() 
{ 
    uint8_t val, i; 

    for(i=0; i<4; i++) 
    { 
     val = lut[i]; 
    } 
} 

Se compilo questo codice ottengo avvertimenti sulla funzione sin. Inoltre nel montaggio non c'è nulla nella sezione .data. Se rimuovo lo sin nella terza riga, ottengo i dati nell'assieme. Chiaramente tutte le informazioni sono disponibili al momento della compilazione.

Puoi dirmi se esiste un modo per ottenere ciò che intendo: il compilatore calcola quanti valori sono possibili offline? O è il modo migliore per utilizzare uno script/programma/... esterno per calcolare le voci della tabella e aggiungerle a un file separato che sarà semplicemente #include d?

+1

"un po 'di sforzo." - con un buon scripting linguaggio? certamente meno, che attaccare il problema con C .... –

+0

C++ 11 (migliorato con C++ 14) ha 'constexpr' come suggerimento al compilatore per eseguire una funzione in fase di compilazione. – johannes

+0

@johannes: 'constexpr' non è un vantaggio. Fornisce semplicemente _allows_ un'espressione valutata al momento della compilazione (e anche costringendo il compilatore a farlo, ad esempio assegnando a un'enumerazione non impedisce di rivalutare in fase di esecuzione in una posizione diversa nello stesso file sorgente!). Non impone o suggerisce nulla. Detto questo, il mio GCC ottimizza lo snippet di codice nell'OP proprio in una tabella di ricerca valutata dal compilerime (senza particolari danze speciali). – Damon

risposta

4

Il problema generale è che sin chiamata rende questa inizializzazione de facto illegale, in base alle regole del linguaggio C, in quanto non è costante espressione per sé e si sta inizializzazione gamma di durata di conservazione statica, che richiede quella. Questo spiega anche perché la tua matrice non è nella sezione .data.

C11 (N1570) §6.6/2,3 espressioni costanti (sottolineatura mia)

Un'espressione costante può essere valutata durante traduzione anziché runtime, e pertanto può essere utilizzato in qualsiasi luogo che una costante può essere essere.

espressioni costanti non dovrà contenere assegnazioni, incremento, decremento, funzione-call, o operatori virgola, tranne quando sono contenuta all'interno di una sottoespressione che non è evaluated.115)

Tuttavia, come nel commento di @ ShafikYaghmour, GCC sostituirà la chiamata di funzione sin con la sua controparte integrata (a meno che l'opzione -fno-builtin sia presente), che probabilmente verrà considerata come espressione costante.Secondo 6.57 Other Built-in Functions Provided by GCC:

GCC include incorporato nelle versioni di molte delle funzioni della libreria standard C . Le versioni con prefisso __builtin_ sono sempre considerati come se avessero lo stesso significato della funzione di libreria C anche se si specifica l'opzione -fno-builtin.

+1

Questo probabilmente funziona perché attualmente [gcc builtins considera la matematica come l'erano espressioni costanti] (http://stackoverflow.com/q/27744079/1708801), using'-fno-builtin' rende il codice simile riuscire utilizzando 'gcc' ma altrimenti genera solo un'avvertenza. –

+0

@ShafikYaghmour: Perché non ci sono dati nello smontaggio. Sono completamente insicuro, cosa succederà se provo ad accedere ai dati ... –

+0

@ChristianWolf: Puoi forzarlo con '__builtin_sin', ma sono d'accordo con Shafik, che probabilmente dovrebbe funzionare. Forse stai usando qualche porta avr-gcc, che non la supporta? –

2

Quello che stai provando non fa parte del linguaggio C. In situazioni come questa, ho scritto il codice seguendo questo schema:

#if GENERATE_SOURCECODE 
int main (void) 
{ 
    ... Code that uses printf to write C code to stdout 
} 
#else 
    // Source code generated by the code above 
    ... Here I paste in what the code above generated 

    // The rest of the program 
#endif 

Ogni volta che avete bisogno di cambiarlo, si esegue il codice con GENERATE_SOURCECODE definito, e si incolla in uscita. Funziona bene se il tuo codice è autonomo e l'output generato cambia solo se cambia il codice che lo genera.

+0

Hai l'inizio della soluzione corretta. – Joshua

+0

Questo non è ottimale nel senso che io sono cross compilazione. Quindi potrebbe o potrebbe non essere ok. Immagino che lo sforzo sia di non lasciare più di due file diversi, dato che tutti i file di intestazione devono essere scambiati e quindi all'interno dei blocchi "# if". Sembra cattivo per me, mi dispiace. –

2

Prima di tutto, è ovvio che dovresti valutare (probabilmente sperimentando) se vale la pena farlo. La tua tabella di ricerca aumenterà le dimensioni dei dati e lo sforzo del programmatore, ma potrebbe o meno fornire un aumento della velocità di runtime di cui hai bisogno.

Se si vuole ancora farlo, non credo che il preprocessore C può farlo semplicemente, perché non ha strutture per l'iterazione o ricorsione.

Il modo più efficace per farlo sarebbe scrivere un programma in C o un'altra lingua per stampare la sorgente C per la tabella, quindi includere quel file nel programma usando il preprocessore. Se si utilizza uno strumento come make, è possibile creare una regola per generare il file di tabella e fare in modo che il file .c dipenda da quel file.

D'altra parte, se si è sicuri che non riusciranno mai a cambiare questa tabella, si potrebbe scrivere un programma per generare una volta e incollarlo in

Problemi correlati