我需要在 GNU 的 c 库中使用 stdlib.h 中的函数 random(),但我在 Windows 上使用 Visual Studio 2008(我没有任何选项。是的,我也讨厌 VS,并且有更好的 RNG在那里)。当 MS 的 stdlib.h 不包含它时,有没有办法使用 GNU random() 函数?
我应该补充一点,我在 MS VS 和 C++ 方面的经验总体上是相当有限的,因为我学习了大部分 Java 编程。
我需要在 GNU 的 c 库中使用 stdlib.h 中的函数 random(),但我在 Windows 上使用 Visual Studio 2008(我没有任何选项。是的,我也讨厌 VS,并且有更好的 RNG在那里)。当 MS 的 stdlib.h 不包含它时,有没有办法使用 GNU random() 函数?
我应该补充一点,我在 MS VS 和 C++ 方面的经验总体上是相当有限的,因为我学习了大部分 Java 编程。
从这里获取源代码,然后分解 stdlib/random_r.c (random()
调用random_r()
所以你不需要random.c
)和相关的头文件(stdlib.h) - 你可能必须从部分制作自己的头文件stdlib,也许还有其他人。
这是一个“补丁”,它可以在没有任何标准库头文件的情况下编译:
--- myrandom.c 2012-12-26 12:25:17.439514392 +0000
+++ ../glibc/stdlib/random_r.c 2012-12-26 12:29:16.581770976 +0000
@@ -51,14 +51,10 @@
* Rewritten to be reentrant by Ulrich Drepper, 1995
*/
-#if 1
-#include "myrandom.h"
-#else
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
-#endif
/* An improved random number generation package. In addition to the standard
@@ -161,7 +157,10 @@
information a given number of times to get rid of any initial dependencies
introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
for default usage relies on values produced by this routine. */
-int srandom_r (unsigned int seed, struct random_data *buf)
+int
+__srandom_r (seed, buf)
+ unsigned int seed;
+ struct random_data *buf;
{
int type;
int32_t *state;
@@ -206,7 +205,7 @@
while (--kc >= 0)
{
int32_t discard;
- (void) random_r (buf, &discard);
+ (void) __random_r (buf, &discard);
}
done:
@@ -216,6 +215,7 @@
return -1;
}
+weak_alias (__srandom_r, srandom_r)
/* Initialize the state information in the given array of N bytes for
future random number generation. Based on the number of bytes we
@@ -228,10 +228,12 @@
Note: The first thing we do is save the current state, if any, just like
setstate so that it doesn't matter when initstate is called.
Returns 0 on success, non-zero on failure. */
-int initstate_r (unsigned int seed,
- char *arg_state,
- size_t n,
- struct random_data *buf)
+int
+__initstate_r (seed, arg_state, n, buf)
+ unsigned int seed;
+ char *arg_state;
+ size_t n;
+ struct random_data *buf;
{
if (buf == NULL)
goto fail;
@@ -271,7 +273,7 @@
buf->state = state;
- srandom_r (seed, buf);
+ __srandom_r (seed, buf);
state[-1] = TYPE_0;
if (type != TYPE_0)
@@ -284,6 +286,7 @@
return -1;
}
+weak_alias (__initstate_r, initstate_r)
/* Restore the state from the given state array.
Note: It is important that we also remember the locations of the pointers
@@ -293,7 +296,10 @@
to the order in which things are done, it is OK to call setstate with the
same state as the current state
Returns 0 on success, non-zero on failure. */
-int setstate_r (char *arg_state, struct random_data *buf)
+int
+__setstate_r (arg_state, buf)
+ char *arg_state;
+ struct random_data *buf;
{
int32_t *new_state = 1 + (int32_t *) arg_state;
int type;
@@ -337,6 +343,7 @@
return -1;
}
+weak_alias (__setstate_r, setstate_r)
/* 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
@@ -349,7 +356,10 @@
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 (struct random_data *buf, int32_t *result)
+int
+__random_r (buf, result)
+ struct random_data *buf;
+ int32_t *result;
{
int32_t *state;
@@ -397,24 +407,4 @@
return -1;
}
-
-// Additional code to show that "it works" ...
-static struct random_data rbuf;
-char state_array[12345];
-
-void init_myrandom(void)
-{
- initstate_r(4711, state_array, sizeof(state_array), &rbuf);
-}
-
-int myrandom(void)
-{
- int rc;
- int32_t res;
- if ((rc = random_r (&rbuf, &res)) > 0)
- {
- return -errno;
- }
- return res;
-}
-
+weak_alias (__random_r, random_r)
[MatsP@linuxhost random]$ diff -u ../glibc/stdlib/random_r.c myrandom.c
--- ../glibc/stdlib/random_r.c 2012-12-26 12:29:16.581770976 +0000
+++ myrandom.c 2012-12-26 12:25:17.439514392 +0000
@@ -51,10 +51,14 @@
* Rewritten to be reentrant by Ulrich Drepper, 1995
*/
+#if 1
+#include "myrandom.h"
+#else
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
+#endif
/* An improved random number generation package. In addition to the standard
@@ -157,10 +161,7 @@
information a given number of times to get rid of any initial dependencies
introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
for default usage relies on values produced by this routine. */
-int
-__srandom_r (seed, buf)
- unsigned int seed;
- struct random_data *buf;
+int srandom_r (unsigned int seed, struct random_data *buf)
{
int type;
int32_t *state;
@@ -205,7 +206,7 @@
while (--kc >= 0)
{
int32_t discard;
- (void) __random_r (buf, &discard);
+ (void) random_r (buf, &discard);
}
done:
@@ -215,7 +216,6 @@
return -1;
}
-weak_alias (__srandom_r, srandom_r)
/* Initialize the state information in the given array of N bytes for
future random number generation. Based on the number of bytes we
@@ -228,12 +228,10 @@
Note: The first thing we do is save the current state, if any, just like
setstate so that it doesn't matter when initstate is called.
Returns 0 on success, non-zero on failure. */
-int
-__initstate_r (seed, arg_state, n, buf)
- unsigned int seed;
- char *arg_state;
- size_t n;
- struct random_data *buf;
+int initstate_r (unsigned int seed,
+ char *arg_state,
+ size_t n,
+ struct random_data *buf)
{
if (buf == NULL)
goto fail;
@@ -273,7 +271,7 @@
buf->state = state;
- __srandom_r (seed, buf);
+ srandom_r (seed, buf);
state[-1] = TYPE_0;
if (type != TYPE_0)
@@ -286,7 +284,6 @@
return -1;
}
-weak_alias (__initstate_r, initstate_r)
/* Restore the state from the given state array.
Note: It is important that we also remember the locations of the pointers
@@ -296,10 +293,7 @@
to the order in which things are done, it is OK to call setstate with the
same state as the current state
Returns 0 on success, non-zero on failure. */
-int
-__setstate_r (arg_state, buf)
- char *arg_state;
- struct random_data *buf;
+int setstate_r (char *arg_state, struct random_data *buf)
{
int32_t *new_state = 1 + (int32_t *) arg_state;
int type;
@@ -343,7 +337,6 @@
return -1;
}
-weak_alias (__setstate_r, setstate_r)
/* 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
@@ -356,10 +349,7 @@
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;
+int random_r (struct random_data *buf, int32_t *result)
{
int32_t *state;
@@ -407,4 +397,24 @@
return -1;
}
-weak_alias (__random_r, random_r)
+
+// Additional code to show that "it works" ...
+static struct random_data rbuf;
+char state_array[12345];
+
+void init_myrandom(void)
+{
+ initstate_r(4711, state_array, sizeof(state_array), &rbuf);
+}
+
+int myrandom(void)
+{
+ int rc;
+ int32_t res;
+ if ((rc = random_r (&rbuf, &res)) > 0)
+ {
+ return -errno;
+ }
+ return res;
+}
+
随机数.h:
#ifndef MYRANDOM_H
#define MYRANDOM_H
#define NULL 0
#define EINVAL 23
typedef int int32_t;
typedef unsigned long size_t;
struct random_data
{
int32_t *fptr; /* Front pointer. */
int32_t *rptr; /* Rear pointer. */
int32_t *state; /* Array of state values. */
int rand_type; /* Type of random number generator. */
int rand_deg; /* Degree of random number generator. */
int rand_sep; /* Distance between front and rear. */
int32_t *end_ptr; /* Pointer behind state table. */
};
#define errno my_errno
extern int my_errno;
static inline void __set_errno(int err) { my_errno = err; };
int random_r (struct random_data *buf, int32_t *result);
int myrandom(void);
void init_myrandom();
#endif
#include <stdio.h>
#include "myrandom.h"
int my_errno;
int main()
{
int i;
init_myrandom();
for(i = 0; i < 100; i++)
{
printf("%d\n", myrandom());
}
return 0;
}
我不保证这将在 Windows 系统上运行,但我会这么认为。除非有一些我没有发现的“gcc-isms”。
我或许还应该指出,标准随机中设置的状态是在random.c的第 137 行左右完成的——要获得与在 gcc 编译的系统中运行 random() 相同的值,你需要复制它。我没有这样做,而是在“init_myrandom”中组成了我自己的一组变量[可能不是最佳的]。