Wonderland
Search…
Code for MS rand() and srand() in VC++ 6.0
My friend created a registration code generator for his software on Windows, and he wanted to transplant it into a web app.
He asked for my help. I think it seems really easy, so I agreed without hesitation. Then a long story began...

# The different results on Windows and Linux

As we know, `srand` will set the current number stored in the memory which is known as seed, and `rand` will use the seed to calculate and return a new number.
The source code of the registration code generator looks like this:
for(int i=0; i<5; i++) {
srand(seed[i]);
strKey.Format(strKey+_T("%c"), _T('A')+rand()%26);
}
The `seed` in the code above is generated from the user's machine id. Now it seems evident that we combine the usages of `rand` of `srand` to generate a static registration code.
I use `cgo` to wrap the origin C++ code, however, the result is not as expected. After some debugging, I found the executing result of `rand` on Linux is different from the one on Windows.

# Digging the source code

/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
same in all the other cases due to all the global variables that have been
set up. The basic operation is to add the number at the rear pointer into
the one at the front pointer. Then both pointers are advanced to the next
location cyclically in the table. The value returned is the sum generated,
reduced to 31 bits by throwing away the "least random" low bit.
Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random number. */
int
__random_r (buf, result)
struct random_data *buf;
int32_t *result;
{
int32_t *state;
if (buf == NULL || result == NULL)
goto fail;
state = buf->state;
if (buf->rand_type == TYPE_0)
{
int32_t val = state;
val = ((state * 1103515245) + 12345) & 0x7fffffff;
state = val;
*result = val;
}
else
{
int32_t *fptr = buf->fptr;
int32_t *rptr = buf->rptr;
int32_t *end_ptr = buf->end_ptr;
int32_t val;
val = *fptr += *rptr;
/* Chucking least random bit. */
*result = (val >> 1) & 0x7fffffff;
++fptr;
if (fptr >= end_ptr)
{
fptr = state;
++rptr;
}
else
{
++rptr;
if (rptr >= end_ptr)
rptr = state;
}
buf->fptr = fptr;
buf->rptr = rptr;
}
return 0;
fail:
__set_errno (EINVAL);
return -1;
}
The source code of Windows `rand` really took me a lot of time to discover the truth, and here let's skip my three-hour search and experimentation. The source code is finally found in an ancient discussion in a forum which is posted in 2003...
Here is the source code of `rand` in VC++ 6.0(or still the same as the one today in Visual Studio 2022...):
static long holdrand = 1L;
int __cdecl rand (void)
{
return(((holdrand = holdrand * 214013L + 2531011L)>>16) & 0x7fff);
}
void __cdecl srand (unsigned int seed)
{
holdrand = (long)seed;
}
and the functions are finally implemented into Typescript:
class WinRandom {
next: number;
rand(this: WinRandom): number {
this.next = this.next * 214013 + 2531011;
return (this.next >> 16) & 0x7fff;
}
srand(this: WinRandom, seed: number) {
this.next = seed;
}
}