2016-07-26 2 views
2

Мое приложение содержит многочисленные идентификаторы. Я хочу, в конечном счете, сделать код доступным для просмотра другими, но не упростить для инженеров, работающих в обратном направлении, поиск легко идентифицируемых идентификаторов. Кроме того, во время разработки полезно иметь постоянные идентификаторы в файлах журналов для упрощения отладки. Но во время выполнения я хотел бы сделать эти идентификаторы случайными, создав их во время компиляции Release. Предлагаемый код с использованием <random> lib приведен ниже в GetRandomId1(). constexpr делает их использование в коде возможно как в операторах switch. Тем не менее, у меня возникают проблемы с использованием constexpr в моей предложенной функции, потому что <random> не является constexpr совместимым. Есть ли другой способ генерации случайных чисел во время компиляции? Или генерирует случайные числа во время компиляции, которые будут использоваться как константы во время выполнения, рассмотренные против концепции constexpr?Замена магических идентификационных номеров случайными идентификаторами, сгенерированными во время компиляции

#include <iostream> 
#include <random> 

// this is the code I would like to use to generate a random number at compile time 
/*constexpr */int GetRandomId1() 
{ 
    std::random_device rd; // non-deterministic seed 
    std::mt19937 gen(rd()); // with constexpr uncommented: 
    // error C3250: 'rd': declaration is not allowed in 'constexpr' function body 
    // error C3249: illegal statement or sub-expression for 'constexpr' function 
    // error C3250: 'gen': declaration is not allowed in 'constexpr' function body 

    std::uniform_int_distribution<> distri(1000, 9999); // with constexpr uncommented: 
    // error C3250: 'distri': declaration is not allowed in 'constexpr' function bod 
    // error C3249: illegal statement or sub-expression for 'constexpr' function 
    // error C2134: 'std::uniform_int<_Ty>::operator()': call does not result in a constant expression 

    return distri(gen); 
} 

// this code is what works so far 
constexpr int GetRandomId2() 
{ 
    return 22; // how to make somewhat random? 
} 

constexpr int AAA = 10; 
//constexpr int AAA = GetRandonId1(); // error: is not constexpr function 
constexpr int BBB = GetRandomId2(); // ok 

void Func1(long ab) 
{ 
    switch(ab) 
    { 
    case AAA: 
     std::cout << AAA << std::endl; 
     break; 

    case BBB: 
     std::cout << BBB << std::endl; 
     break; 
    } 
} 

int main() 
{ 
    Func1(22); // ok: prints 22 

    return 0; 
} 

Ищу прямой вперед, ремонтопригодны решение, как один я предложил и в отличие от интенсивного использования шаблонов, как предложено в How can I generate dense unique type IDs at compile time?. Также в этой публикации @jmihalicza указывает на исследовательскую работу Random number generator for C++ template metaprograms. В данной статье описывается генерация случайных чисел во время компиляции с использованием метапрограммирования шаблонов, что представляет собой сложную попытку, которая выполняет задачу, для которой был разработан IMO constexpr (осмелюсь сказать или должен был быть?).

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

+6

Вы всегда можете добавить пользовательский шаг предварительной сборки, который генерирует случайные числа в файл, чтобы быть '# include'd – sp2danny

ответ

4

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

Я думаю, что это сопоставимая криптографическая защита для mt19937, которая является (очень сложной) линейной генератор обратной связи и не имеет криптографической защиты в любом случае.

Идея в этом коде заключается в использовании __TIME__ и __LINE__ в качестве семени для генератора.

typedef uint32_t u32; 
typedef uint64_t u64; 
typedef unsigned char uchar; 

template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL<<31)-1> 
struct LinearGenerator { 
    static const u32 state = ((u64)S * A + C) % M; 
    static const u32 value = state; 
    typedef LinearGenerator<state> next; 
    struct Split { // Leapfrog 
     typedef LinearGenerator< state, A*A, 0, M> Gen1; 
     typedef LinearGenerator<next::state, A*A, 0, M> Gen2; 
    }; 
}; 

// Metafunction to get a particular index from generator 
template<u32 S, std::size_t index> 
struct Generate { 
static const uchar value = Generate<LinearGenerator<S>::state, index - 1>::value; 
}; 

template<u32 S> 
struct Generate<S, 0> { 
    static const uchar value = static_cast<uchar> (LinearGenerator<S>::value); 
}; 


// Seed 

#define RNG_SEED ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \ 
       (__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \ 
       (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) + \ 
       (__LINE__ * 100000) 

Я не пытался переписать с помощью constexpr вместо шаблонов, но ТБМ я думаю, что в C++ 11 стандартных с использованием constexpr функций для чего-либо вообще сложного не значительно лучше, чем шаблоны. Это действительно действительно приятно в стандарте C++ 14, когда вы действительно можете иметь локальные переменные и так далее.

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

Вам обязательно нужно отказаться от мечты разговаривать с std::random_device во время компиляции. IIRC, в исполнении libc++, то есть в основном тонкая обертка над std::fopen("/dev/urandom"). Я не знаю ни одного стандарта или предложения C++, которые позволяли бы выполнять операции с файловой системой в пределах вычислений constexpr. :)

+0

Что значит стать« криптографически безопасным »? Почему это необходимо во время компиляции? Это обоснование «constexpr»? К моему способу мышления, так как программист управляет кодом в области какой-либо конкретной функции 'constexpr', тогда он должен решить, что следует рассматривать как' const' для остальной части программы. Решение не более чем решение во время компиляции, является ли переменная-член открытой, частной или защищенной. – rtischer8277

+0

Вопрос в том, какой код должен выполнять компилятор для создания литерала типа 'constexpr'? Должен ли он быть только заголовком, как для метапрограммирования, как ваше решение? Недопустимо значение 'constexpr'. Должен ли он быть отнесен к внешнему файловому коду? Также не хватает смысла. – rtischer8277

+0

Я думаю, у вас есть некоторые недоразумения о том, что такое 'constexpr'. 'constexpr' - это не то же самое, что' const', это действительно не имеет ничего общего с 'public, private' и т. д. Это также не имеет никакого отношения к включению оптимизаций компилятора - если компилятор способен вычислять выражение в compile- времени, он уже свободен для оптимизации в соответствии с правилом as-if. Наиболее значительным преимуществом 'constexpr' является то, что литералы могут использоваться в качестве параметров шаблона. –

Смежные вопросы