RAND_MAX宏:签名还是未签名?

Ale*_*nze 14 c

我已经查看了C标准(从1999年开始)并且它只说RAND_MAX至少应该是32767但是没有说明这个宏是否应该扩展为signed或unsigned int.Single UNIX Specification(链接1,链接2)和Linux man(链接)不会增加任何清晰度.

人们会认为RAND_MAX应该是一个,signed int因为这是rand()回报.

但是,我发现有些编译器将它定义为无符号:

  • 古老的Turbo C++ 1.01:#define RAND_MAX 0x7FFFU
  • 不那么古老的C++ Builder 5.5:#define RAND_MAX 0x7FFFU
  • 仍然活着的Open Watcom C/C++ 1.9:#define RAND_MAX 32767U
  • DJGPP(用于DOS的gcc 3.3.4):#define RAND_MAX 2147483647
  • MinGW(适用于Windows的gcc 4.6.2):#undefine RAND_MAX 0x7FFF
  • MS Visual Studio 2010(链接):RAND_MAX定义为值0x7fff
  • Tiny C编译器0.9.25:#define RAND_MAX 0x7FFF
  • lcc-win32 3.8:#define RAND_MAX 0x7fff
  • Pelles C 6.50:#define RAND_MAX 0x3fffffff OR #define RAND_MAX 0x7fff
  • Digital Mars C/C++ 8.52:#define RAND_MAX 32767

由于签署了未签名的促销活动,这使得看似无害的代码如下所述变得不便携并且爆炸:

cos(w * t) + (rand() - RAND_MAX / 2) * 0.1 / (RAND_MAX / 2);
Run Code Online (Sandbox Code Playgroud)

rand()返回signed int范围[0,RAND_MAX]中的a.

如果RAND_MAX定义为a unsigned int,则来自的值也会rand()被提升unsigned int.

如果是这种情况,则差异(rand() - RAND_MAX / 2)变为无符号整数的无符号差,其范围为[0,RAND_MAX- RAND_MAX/ 2]和[ UINT_MAX+ 1- RAND_MAX/ 2,UINT_MAX-1],而不是有符号整数与有符号整数的有符号差.值范围为[ - RAND_MAX/ 2,RAND_MAX- RAND_MAX/ 2].

无论如何,似乎RAND_MAX应该签名并且大多数(?)编译器都这样定义它,但有没有任何权威来源说它应该签名?较旧的标准?K&R?另一个UNIX规范?

Jen*_*edt 7

是的,这看起来像是标准中的缺陷.

首先,现在可能没人会定义rand()返回int.意图显然是返回正数,并且没有可以使用负回报的错误返回.如果今天引入的这个函数将被设计为使用无符号整数类型作为返回类型.我的猜测是它早于C89并且将无符号整数的概念引入语言.

然后,显然人们必须期望函数返回的最大值的定义与函数的类型相同.在其他地方,宏被定义为扩展到具有某种类型的表达式,所以这也是可能的.

至于你的问题,我认为最容易携带的东西是[0, 1)通过做类似的事情将值首先缩放到double,rand()/(RAND_MAX+1.0)然后从那里获得所有的计算.在任何情况下,rand()如果您的平台没有更好的伪随机生成器,您应该仅作为最后的手段使用.例如,在POSIX系统上,该rand48系列是一个方便的替代品,具有良好的描述属性

  • @R ..意见反对意见:我认为它会,而且`RAND_MAX`将是无符号返回类型的最大值.没有理由在这里浪费一点符号,并且没有随机"数字"容易构成更宽的随机位向量. (3认同)

小智 3

答案是:该代码做出了没有根据的假设,因此需要修复。该代码应该做的事情是在使用时强制RAND_MAX转换(int)

虽然编译器将其宏定义为有符号会更有意义RAND_MAX,但该标准小心地避免要求它们这样做。这使得任何代码盲目地假设它被签名都是一个可移植性错误。