【发布时间】:2012-05-29 07:43:36
【问题描述】:
我查看了 C 标准(从 1999 年开始),它只说 RAND_MAX 至少应为 32767,但没有说明此宏应扩展为有符号整数还是无符号整数。 Single UNIX Specification (link 1, link 2) 和 Linux man (link) 并没有增加任何清晰度。
人们会认为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(gcc 4.6.2 for Windows):#define RAND_MAX 0x7FFF
- MS Visual Studio 2010 (link):RAND_MAX 定义为值 0x7fff
- 微型 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
- 数字火星 C/C++ 8.52:#define RAND_MAX 32767
这使得像下面这样看似无害的代码变得不可移植并且由于已签名到未签名的提升而崩溃:
cos(w * t) + (rand() - RAND_MAX / 2) * 0.1 / (RAND_MAX / 2);
rand() 在 [0,RAND_MAX] 范围内返回一个 signed int。
如果RAND_MAX 被定义为unsigned int,则来自rand() 的值也会提升为unsigned int。
如果是这种情况,(rand() - RAND_MAX / 2) 的差值将变为无符号整数的无符号差,其值在 [0,RAND_MAX-RAND_MAX/2] 和 [UINT_MAX+1-@987654341 范围内@/2,UINT_MAX-1] 而不是带符号整数的有符号差,其值在 [-RAND_MAX/2,RAND_MAX-RAND_MAX/2] 范围内。
无论如何,RAND_MAX 似乎应该被签名并且大多数(?)编译器都这样定义它,但是是否有任何权威来源说它应该被签名?旧标准? K&R?另一个 UNIX 规范?
【问题讨论】:
-
Plaguer & Brodie (1989) 编写的关于 ANSI/ISO 标准的Standard C一书说
RAND_MAX是<integer constant expression ≥ 32767>。 K&R 的 The C Programming Language(1988 年第 2 版)仅提及它与int rand()函数有关,称后者返回的值在0到RAND_MAX范围内。听起来我签名了。 -
@martineau 对我来说听起来不详。
integer不代表int,unsigned和integer一样int。 -
不合格的
int等价于signed或signed int,因此将相同的规则与语言规范中“整数”一词的所有用法相关联是合理的。除此之外,事实是RAND_MAX的唯一目的是提供一些东西来描述int rand()函数返回的值的限制,这只会进一步加强这一假设。即为什么#define是unsigned数量,它仅用于指定返回signed数量的库函数的可能返回值范围? -
@martineau 除了标准不禁止(=允许)之外,我不知道为什么。问题的重点是试图找到一个不合理的假设(我们对此部分没有问题),而是在当前标准(或其前身,包括 K&R)中明确要求
RAND_MAX的位置被签名(甚至可能是未签名)或将被明确允许被签名或未签名。当前的措辞隐含地允许两者。这可能是出于历史(=兼容性)的原因,以免使现有的未签名实现无效。
标签: c