请注意-我没有编写此代码,我只是在尝试维护/改进它。
我的头文件之一包含以下几行:
/* macros to seed the random number generator */
/* This is needed on Windows which throws an error due to 'random'
not being defined on MingW. I'll clean it up later. */
#define srandom srand
#define random rand
/* New random seed function. */
#define srand srandom
#define rand random
#define rnd(x) ((int)(rand() % (x)) + 1)
#define rund(x) ((int)(rand() % (x)))
此外,我具有所有四个功能rand
,srand
,random
,srandom
的手册页,因此我假设它们都是有效的C函数。 / p>
您能帮我理解/弄清楚我打电话给rnd(10)
时会发生什么吗?这是未定义的行为吗?一个定义是否以某种方式“替代”另一个?
(我问是因为我觉得我的实际程序中有很多数字,即使我的测试程序似乎可以正常工作并且随机分布。)
请快速注意一下,我几乎肯定我所看到的“大量低数”可能是运算符优先级和括号中的错误,导致长布尔值始终评估为“ true”。
答案 0 :(得分:3)
递归预处理器宏的效果是明确定义的:在扩展宏foo
的定义时,如果再次找到名称foo
,则将其保留。因此,在您的情况下,rand
扩展到random
,然后扩展到rand
,然后再不扩展。
从技术上讲,如果您的代码还包含stdlib.h
,则这些定义的行为是不确定的,因为如果您定义(或取消定义)其名称也是标准库函数名称的宏,则该行为是不确定的由包含的标头拉入。实际上,如果标准库头仅将这些名称定义为函数而不是宏,则这些宏定义将不起作用。如果它们将名称定义为宏,则会出现编译错误。
函数rand
和srand
由核心C语言定义,并且只要您包含stdlib.h
就可以使用(某些嵌入式实现不提供完整的C库除外) 。 random
和srandom
是Unix / POSIX的附加内容,要使用它们,您需要在#define _XOPEN_SOURCE 500
之前定义一个符号,例如#include <stdlib.h>
。
我很困惑这些定义如何解决MinGW上的任何问题。如果MinGW根本没有定义random
,则预处理器会将调用random()
扩展为random()
,并且仍然尝试调用未定义的函数。看起来好像是一系列连续的黑客攻击造成了无害的剩余杂物,或者有人摸索着解决了一个问题,最终以不同的方式解决了这个问题,但是即使这并没有对解决方案有所帮助,还是犯了这部分。
答案 1 :(得分:2)
对于给定的扩展,C预处理器不会多次评估同一宏扩展。也就是说,一旦识别出周期,它将打破周期。因此,在您的情况下,将发生以下扩展:
rnd(10) // list of available macros: [srandom, random, srand, rand, rnd(x), rund(x)]
((int)(rand() % (10)) + 1) // list of available macros: [srandom, random, srand, rand, rund(x)]
((int)(random() % (10)) + 1) // list of available macros: [srandom, random, srand, rund(x)]
((int)(rand() % (10)) + 1) // list of available macros: [srandom, srand, rund(x)]
在最后一步,预处理器将找不到更多可用的扩展(已完成rand的操作)并将放弃。
这与为什么您看到的小数字多于大数字无关。这可能与RAND_MAX
的不同定义有关。在一个非常人为的示例中,如果RAND_MAX = 10
,则0出现的可能性为18%,而其他数字出现的可能性为9%。不仅如此,典型的rand实现对于较低位倾向于具有较低的熵。如果对您来说重要的是要有一个统一的发行版,那么您可能需要在标准库之外查找。
答案 2 :(得分:0)
您的编译器有一个神奇的选项-E来查看扩展。
int foo(int x)
{
return rand(x);
}
int foo(int x)
{
return rnd(x);
}
扩展到
int foo(int x)
{
return rand(x);
}
int foo(int x)
{
return ((int)(rand() % (x)) + 1);
}
BTW IMO最好改用内联函数。
答案 3 :(得分:0)
在blue paint algorithm中,一个符号不能被多次评估。 rand
返回后,random
被涂成蓝色,因此rand
将不再扩展为random
。
答案 4 :(得分:-2)
似乎第一个预处理器将更新源并将srand
替换为srandom
,然后它将再次更新源并将srandom
替换为srand
。我已经检查过cpp
,看起来还可以。程序也可以正常工作。我对srand
宏有个新的想法,因为stdlib.h
中有一个函数具有相同的名称,但没有发生任何不好的事情。