2011-09-30 15 views
8

Attualmente sto lavorando su un progetto di codice che richiede di sostituire certe stringhe con gli hash di quelle stringhe. Visto che queste stringhe non cambieranno in fase di esecuzione, sarebbe vantaggioso, in termini di efficienza, far sì che il preprocessore c esegua la mia funzione di hash su ogni stringa dichiarata come hash in fase di compilazione.Come far sì che il preprocessore C esegua il codice durante la compilazione?

C'è un modo per ottenere il preprocessore C per eseguire la mia funzione di hash in fase di compilazione?

So che questo non funziona come descritto sopra, ma solo per avere un'idea di dove sto andando, ecco alcuni pseudocodici che utilizzano una macro. Immaginate che invece di espandere la macro, il preprocessore ha la funzione di hash e ampliato per il valore di ritorno di quella funzione di hash:

#include <iostream> 
    #include <string> 

    #define U64_HASH(inputString) getU64HashCode(inputString) 

    //my hash function 
    unsigned long long getU64HashCode (string inputString) 
    { 
     /*code*/ 
    } 

    int main() 
    { 
     cout << U64_HASH("thanks for helping me") << endl; 
     return 0; 
    } 

Anche in questo caso, idealmente il cout << U64_HASH("thanks for helping me") << endl; si espanderebbe a cout << 12223622566970860302 << endl;

ho scritto un generatore di file di intestazione, e questo funziona bene per questo progetto.

Soluzione Finale

ho deciso di utilizzare John Purdy's perl script per questo progetto, in quanto è semplicemente impressionante, e mi permette di alimentare l'uscita che voglio direttamente al mio compilatore. Grazie mille, John.

+0

Non senza qualche magia pazzo. –

+0

C++ 11 ha letterali definiti dall'utente e constexpr. Questi potrebbero essere utili. – Pubby

+1

potresti sempre "# definire" quelle stringhe come i loro hash? AFAIK il preprocessore C non ha alcuna possibilità di eseguire codice. – Serdalis

risposta

6

Un modo per farlo è quello di mettere tutte le stringhe in un file di intestazione, e assegnare loro un nome:

// StringHeader.h 
#define helloWorld    "Hello World" 
#define error_invalid_input  "Error: Invalid Input" 
#define this_could_get_tedious "this could get tedious" 

quindi è possibile utilizzare quelle stringhe:

#include "StringHeader.h" 
std::cout << this_could_get_tedious << std::endl; 

Quindi è possibile eseguire un programma sul tuo StringHeader.h di hash ogni stringa, e generare un file di intestazione di sostituzione:

// Generated StringHeader.h 
#define helloWorld    097148937421 
#define error_invalid_input  014782672317 
#define this_could_get_tedious 894792738384 

Questo sembra molto manuale e noioso, all'inizio, ma ci sono modi per automatizzarlo.

Ad esempio, è possibile scrivere qualcosa per analizzare il codice sorgente, cercando "stringhe tra virgolette". Quindi è possibile assegnare un nome a ogni stringa, scriverlo su un singolo StringHeader.h e sostituire la stringa quotata inline con la nuova costante di stringa denominata. Come passo aggiuntivo, quando crei il file, puoi eseguire l'hashing di ogni stringa, oppure il file può essere inserito in una volta sola dopo averlo creato. Ciò potrebbe consentire di creare una versione hash e non hash del file (che potrebbe essere utile per creare una versione di debug non hash e una versione di rilascio con hash).

Se lo si prova, il parser iniziale per cercare le stringhe dovrà gestire i casi limite (commenti, #include righe, stringhe duplicate, ecc.).

0

Se non è possibile ottenere il pre-processore per farlo, è possibile scrivere il proprio pre-processore per eseguire prima questo passaggio.

+1

Sì, lo sto considerando e lo farò se necessario, ma voglio davvero usare il preprocessore standard se posso. –

0

Non c'è modo di forzarlo, ma se il compilatore è abbastanza buono, può farlo. Gioca con le sue opzioni di ottimizzazione e studia lo smontaggio del codice nel debugger per vedere se qualcuna di esse ti consente di ottenere ciò che desideri.

+3

Puoi nominare un singolo compilatore che farà ciò di cui stai parlando? –

+1

Tutto ciò che devi fare è scrivere l'hash completo nella macro stessa, quindi il compilatore dovrebbe vederlo come un'espressione costante e sostituire il valore (supponendo che le impostazioni di ottimizzazione lo consentano). Facile! * (* Difficile) – geofftnz

+0

@David: Penso che il compilatore DMD possa farlo tramite CTFE :) Anche se sono curioso di sapere se è possibile in C++. Non ne ho mai sentito parlare –

6

Se un compilatore supporta mai presente, C++ 11 ha user defined literals:

constexpr unsigned long long operator "" U64_HASH_(
    const char *literal_string) { ... } 

#define U64_HASH(inputString) inputString U64_HASH_ 

o con constexpr:

constexpr unsigned long long operator "" U64_HASH(
    const char *literal_string) { ... } 
+0

È garantito che restituisce il valore hash per i valori letterali stringa? –

Problemi correlati