Как заставить препроцессор C выполнять код во время компиляции? - PullRequest
8 голосов
/ 30 сентября 2011

В настоящее время я работаю над проектом кода, который требует, чтобы я заменил определенные строки хэшами этих строк.Учитывая, что эти строки не изменятся во время выполнения, было бы целесообразно с точки зрения эффективности, чтобы препроцессор 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;

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

Окончательное решение

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

Ответы [ 4 ]

6 голосов
/ 30 сентября 2011

Если компилятор когда-либо поддерживает это, 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) { ... }
6 голосов
/ 30 сентября 2011

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

// 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 и заменить встроенную строку в кавычках новой именованной строковой константой.В качестве дополнительного шага при создании файла вы можете хэшировать каждую строку - или вы можете получить файл за один раз после того, как создали его.Это может позволить вам создать хешированную и не хэшированную версию файла (что может быть полезно для создания нехэшированной версии Debug и хэшированной версии Release).

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

0 голосов
/ 30 сентября 2011

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

0 голосов
/ 30 сентября 2011

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

...