用编译时生成的随机ID替换魔术ID号

时间:2016-07-26 15:20:27

标签: c++11 random constexpr

我的应用包含众多ID。我想最终让其他人可以查看代码,但是不要让运行时反向工程师轻松查找容易知道的ID。此外,在开发期间,在日志文件中具有常量ID以便于调试是有帮助的。但是在运行时我想通过在Release编译期间生成这些ID来使它们随机。使用<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(我敢说或应该已经?)设计的任务。

由于应用程序架构原因,我不必担心ID冲突,所以这不是一个问题。应用程序代码将确保不会返回重复项。

1 个答案:

答案 0 :(得分:5)

前段时间我提供了一个constexpr随机数生成器here,用于constexpr字符串加密的相关目的,以帮助您关注与之相关的对手。

我认为它具有与mt19937类似的加密安全性,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")上的薄包装器。我不知道任何允许constexpr计算中的文件系统操作的C ++标准或提议。 :)