Как заставить препроцессор C выполнять код во время компиляции?

В настоящее время я работаю над проектом кода, который требует от меня заменить определенные строки хэшами этих строк. Поскольку эти строки не будут меняться во время выполнения, было бы выгодно, чтобы препроцессор c запускал мою хэш-функцию для каждой строки, которую я объявляю хэшированной во время компиляции.

есть ли способ получить C препроцессор для запуска моей хэш-функции во время компиляции?

Я знаю, что это не работает так, как я описано выше, но чтобы получить представление о том, куда я иду, вот некоторый псевдокод, который использует макрос. Представьте, что вместо простого расширения макроса препроцессор запустил хэш-функцию и расширил ее до возвращаемого значения этой хэш-функции:

    #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;
    }

опять же, в идеале cout << U64_HASH("thanks for helping me") << endl; будет увеличен до cout << 12223622566970860302 << endl;

я написал генератор заголовочных файлов, и это отлично работает для этого проекта.

финал Решение

я решил использовать Перл-скрипт Джона Перди для этого проекта,так как это просто потрясающе, и позволяет мне кормить вывод, который я хочу непосредственно моему компилятору. Большое спасибо, Джон.

4 ответов


один из способов сделать это-поместить все ваши строки в файл заголовка и назвать их:

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

затем вы можете использовать эти строки:

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

затем вы можете запустить программу на вашем StringHeader.h для хэша каждой строки и создания файла заголовка замены:

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

это выглядит очень ручным и утомительным, сначала, но есть способы автоматизировать его.

например, вы можете написать что - то, чтобы разобрать исходный код, ища " цитата струнные." Тогда он мог бы назвать каждую строку, записать ее в один StringHeader.h и замените встроенную строку с кавычками новой именованной Строковой константой. В качестве дополнительного шага при создании файла вы можете хэшировать каждую строку - или вы можете иметь файл за один раз после его создания. Это может позволить вам создать хэшированную и не хэшированную версию файла (что может быть полезно для создания не хэшированной отладочной версии и хэшированной версии выпуска).

если вы попробуете это, ваш инициал парсер для поиска строк должен будет обрабатывать крайние случаи (комментарии, #include строки, дублированные строки и т. д.).


если компилятор когда-либо поддерживает это, C++11 имеет пользовательские литералы:

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

#define U64_HASH(inputString) inputString U64_HASH_

или constexpr:

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

Если вы не можете заставить предварительный процессор сделать это за вас, вы можете написать свой собственный предварительный процессор, чтобы сделать этот шаг первым.


нет способа заставить его, но если ваш компилятор достаточно хорош, он может это сделать. Играйте с его параметрами оптимизации и изучите разборку кода в отладчике, чтобы узнать, позволяет ли какой-либо из них достичь желаемого.