2016-07-26 47 views
2

我的應用包含大量ID。我想最終讓代碼可以被其他人查看,但是不能讓運行時反向工程師輕鬆查找容易識別的ID。另外,在開發過程中,日誌文件中的常量ID有助於更輕鬆地進行調試。但在運行時,我想通過在Release編譯期間生成這些ID來隨機生成這些ID。使用<random>庫建議的代碼可以在GetRandomId1()下面看到。 constexpr使它們在代碼中的使用可能像在switch語句中一樣。但是,我在使用constexpr時遇到了麻煩,因爲<random>constexpr不兼容。有沒有另外一種方法在編譯時產生隨機數字?或者在編譯時產生隨機數,在運行時用作常量,這與constexpr的概念相反?使用在編譯時生成的隨機ID替換魔幻ID號

#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所設計的任務(我敢說,或者應該這樣做)。

由於應用程序體系結構的原因,我不必擔心ID衝突,因此這不是問題。應用程序代碼將確保不會有重複項返回。

+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代替模板重寫,但TBH我想在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'等無關。它也與啓用編譯器優化無關 - 如果編譯器能夠在編譯時計算表達式,時間,它已經可以根據as-if規則進行優化。 'constexpr'最顯着的好處是文字類型可以用作模板參數。 –