How to generate a series of random numbers with the C/C++ preprocessor
I would like to generate a series of random numbers with the C preprocessor, and store them in variables for use by my program.
OBJECTIVES:
I would like to generate a "unique" set of random numbers every time I build my program. A small subset of the variables storing the random numbers will be overwritten with meaningful (i.e. non-random) numbers. I would like it to be impossible for a hacker, by debugging the program or comparing multiple builds, to be able to differentiate the meaningful numbers from the random numbers. I would like the build process to be automated and self-contained. I would like the implementation to be portable across Visual Studio and GCC.
CLARIFICATIONS:
- The calculations must be done at compile time, not at program execution. Anyone debugging the program should only be able to see, for example, a variable being initialized to a constant (the random number).
- The random numbers should be integers.
- The random number generator should be seeded, in some manner, from
__DATE__
and__TIME__
, so that different builds will yield different random numbers. - It would be preferable, but not absolutely necessary, to be able to specify a range for the random numbers (e.g. from 1 to 100).
- It would be preferable, but not absolutely necessary, to be able to specify the total number of random numbers to generate (e.g. declare 1000 variables and initialize each to a random number).
ATTEMPTS SO FAR:
- 开发者_开发技巧
- Previous thread on arithmetic in the preprocessor: Can the C preprocessor perform integer arithmetic? The take-away is that the #if condition can evaluate arithmetic.
- Googling reveals that besides arithmetic, shift and bit operations can also be evaluated by the #if. I have confirmed this with Visual Studio C++.
Candidates for simple random number generators: http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369B5E30.65A55FD1@stat.fsu.edu Any one of these generators, or any generator that is impossible to reverse engineer from a given series of random numbers, would be fine because I don't need a particularly well behaved generator. For the sake of this exercise, we can use the following as an example:
unsigned long jcong=380116160; #define CONG (jcong=69069*jcong+1234567)
I think the basic problem is that there is state that is stored in the variable jcong between successive calls to the generator. Variable assignment is not supported in the preprocessor, as far as I know. Perhaps there is some clever recursive macro that can do the trick?
The closest I could get, but not satisfying my objective of being performed by the preprocessor, is:
unsigned long jcong=380116160; unsigned long randomBlock[] = {jcong=69069*jcong+1234567, jcong=69069*jcong+1234567};
I have confirmed in Visual Studio C++ that this does indeed initialize the array members to different random numbers. However, the debugger still steps through the initialization.
This is a pure programming/implementation question, so please, no proselytizing on the evils of the preprocessor or the futility of fighting hackers.
So, here is the solution that is close to requirements:
// pprand.h
#include <boost/preprocessor/slot.hpp>
#ifndef PP_RAND_SEED
#define PP_RAND_SEED (((PP_RAND_MIN + PP_RAND_MAX) * 0x1f7) ^ 0x1e3f75a9)
#endif
#define BOOST_PP_VALUE ((PP_RAND_SEED * 214013 + 2531011) % 65536)
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#undef PP_RAND_SEED
#define PP_RAND_SEED BOOST_PP_SLOT(1)
#define BOOST_PP_VALUE (PP_RAND_MIN + PP_RAND_SEED % (PP_RAND_MAX - PP_RAND_MIN))
#include BOOST_PP_ASSIGN_SLOT(2)
#undef BOOST_PP_VALUE
#ifdef PP_RAND
#undef PP_RAND
#endif
#define PP_RAND BOOST_PP_SLOT(2)
You can use it like this:
// Pseudo random number range.
#define PP_RAND_MIN 0
#define PP_RAND_MAX 100
// Pseudo random number seed.
#define PP_RAND_SEED 123
#include "pprand.h"
// Got it!
#pragma message("PP_RAND value:" _CRT_STRINGIZE(PP_RAND))
To read more about this approach visit my blog: http://alexander-stoyan.blogspot.com/2012/07/getting-pseudo-random-numbers-at.html
You have to replace the Random generator sequence with something that actually generates acceptable semi-random values, but that part should be easy.
You have to define a random seed with -DSEED=...
at compilation.
No idea how to do that with __TIME__
and __DATE__
because they are strings.
#include <stdio.h>
template <int N>
struct Random {
enum { value = 7 * Random<N-1>::value + 17 };
};
template <>
struct Random<1> {
enum { value = SEED};
};
template <int N, int BEG, int END>
struct RandomIn {
enum { value = BEG + Random<N>::value % (END-BEG) };
};
int main() {
printf("%d %d", RandomIn<2, 5, 10>::value, RandomIn<3, 5, 10>::value);
return 0;
}
精彩评论