2011-09-30 13 views
8

Actualmente estoy trabajando en un proyecto de código que me obliga a reemplazar ciertas cadenas con hashes de esas cadenas. Viendo que estas cadenas no cambiarán en el tiempo de ejecución, sería ventajoso, en términos de eficiencia, tener el preprocesador c ejecutando mi función hash en cada cadena que declaro que es hash en el momento de la compilación.¿Cómo hacer que el preprocesador C ejecute el código durante la compilación?

¿Hay alguna forma de obtener el preprocesador C para ejecutar mi función hash en tiempo de compilación?

Sé que esto no funciona de la manera que describí anteriormente, pero solo para tener una idea de hacia dónde voy, aquí hay un pseudocódigo que usa una macro. Imagine que en lugar de simplemente la expansión de la macro, el preprocesador corrió la función hash y lo amplió para el valor de retorno de esa función 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; 
    } 

Una vez más, idealmente el cout << U64_HASH("thanks for helping me") << endl; se expandiría a cout << 12223622566970860302 << endl;

escribí un generador de archivos de cabecera, y eso funciona bien para este proyecto.

Solución Final

he decidido utilizar John Purdy's perl script para este proyecto, ya que es simplemente impresionante, y me permite alimentar la salida Quiero directamente a mi compilador. Muchas gracias, John.

+0

No sin algo de magia loca. –

+0

C++ 11 tiene literales definidos por el usuario y constexpr. Esos podrían ser útiles. – Pubby

+1

siempre podría '# definir' esas cadenas como sus hashes? AFAIK el preprocesador C no tiene ninguna capacidad de ejecutar código. – Serdalis

Respuesta

6

Una forma de lograr esto es poner todas sus cadenas en un archivo de cabecera, y nombrarlos:

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

continuación, puede utilizar esas cadenas:

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

A continuación, puede ejecutar una programa en su StringHeader.h en hash cada cadena, y generar un archivo de cabecera de reemplazo:

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

Parece muy manual y tedioso, al principio, pero hay formas de automatizarlo.

Por ejemplo, podría escribir algo para analizar su código fuente, buscando "cadenas entre comillas". Luego podría nombrar cada cadena, escribirla en un solo StringHeader.h y reemplazar la cadena entrecomillada en línea con la nueva constante de cadena con nombre. Como un paso adicional cuando crea el archivo, puede hash cada cadena, o podría tener el archivo de una vez después de haberlo creado. Esto podría permitirle crear una versión hash y no hash del archivo (lo que podría ser útil para crear una versión de depuración sin hash y una versión de lanzamiento hash).

Si lo intenta, su analizador inicial para buscar cadenas tendrá que manejar casos extremos (comentarios, # líneas de inclusión, cadenas duplicadas, etc.).

0

Si no puede hacer que el pre-procesador lo haga por usted, es posible que pueda escribir su propio pre-procesador para realizar este paso primero.

+1

Sí, estoy considerando eso y lo haré si es necesario, pero realmente quiero usar el preprocesador estándar si puedo. –

0

No hay forma de forzarlo, pero si su compilador es lo suficientemente bueno, puede hacerlo. Juega con sus opciones de optimización y estudia el desmontaje del código en el depurador para ver si alguno de ellos te permite lograr lo que deseas.

+3

¿Puedes nombrar un solo compilador que hará lo que estás hablando? –

+1

Todo lo que tiene que hacer es escribir el hash completo en la macro misma, luego el compilador debe verlo como una expresión constante y sustituir el valor (suponiendo que la configuración de optimización lo permita). Easy! * (* Hard) – geofftnz

+0

@David: Creo que el compilador de DMD puede hacerlo a través de CTFE :) Aunque también tengo curiosidad si es posible en C++. Nunca he oído hablar de él –

6

Si un compilador nunca lo admite, C++ 11 tiene 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

¿Se garantiza que devolverá el valor hash para los literales de cadena? –

Cuestiones relacionadas