为什么std::rand()的返回类型不是unsigned int?

31

std::rand 的文档中写道:

int rand();
返回一个介于​0​和RAND_MAX(包括​0​和RAND_MAX)之间的伪随机整数值。

由于保证返回的是非负整数,为什么返回类型是有符号的?

我不是在讨论是否应该在这里使用它。这是历史问题还是一些设计上的失误?


1
可能是因为在早期,int 被认为是一种一流类型。(K&R C 的遗产?) 请注意,相对较少的语言支持无符号类型。 - user1196549
16
如果RAND_MAX小于2的31次方(通常远小于该值),则将其声明为无符号的并没有好处,但存在一些缺点,例如如果有人执行rand() % 100 - 50操作,则可能会得到意外的结果。 - Alan Birtles
6
请注意,rand()函数是一个非常古老的函数。在C语言标准化之前就已经存在了。甚至有可能在该语言添加无符号整数之前就已经被创建了。 - freakish
7
这是一个历史性的问题。回想起来, rand()/srand() 函数在 C 语言支持无符号(或长整型)类型之前就已经被规定了。那时候,大多数 C 语言实现都只有16位的 int 类型,只有少数才有32位的 int 类型,这就是为什么 RAND_MAX 只需要被要求为32767(或更高)。无符号和长整型(以及其他一些类型)是在 Unix 被用 C 重写(1973年)时引入的。随后的 C 语言进化(包括 C89 标准)保持向后兼容,并且根据 ARM 的说法,第一个 C++ 标准也要尽可能地保持与 C89 的兼容性。 - Peter
2个回答

42

关于unsigned有很多争论。不过,我们不需要深入主观领域,考虑如下:重要的不是从rand()返回的值是否可能为负数,而是rand()返回一个特定类型的值,该类型决定您可以对该值执行什么操作。 rand()从不返回负值,但将对该值应用使其成为负值的操作有意义吗?当然有。例如,您可能想执行以下操作:

 auto x = rand() % 6 - 3;
如果 rand() 返回一个无符号数,那么在看似正常的代码中会导致令人困惑的错误。例如,对于索引来说,使用无符号数是另一回事情。索引总是为正数。如果您要对它应用将其值变为负数的操作,那么它就不再是一个索引了。而 rand() % 6 -3 则是一个随机数,无论它是正数还是负数。

类型 不仅仅是它可以表示的值的范围。有符号和无符号整数具有不同的语义。请注意,C++20 引入了 std::ssize。它是容器的大小,它只能是正数。尽管如此,它是有符号的。这是一个例子,即使是正值也是有符号的,仅仅是为了允许有符号的算术运算。此外,将 std::size 更改为返回有符号数是不可取的,因为那样会破坏现有的代码。

另外,值得一提的是,Java 根本没有无符号整数类型,因为无符号算术被认为太令人困惑了。

2
感谢您的回答。@Alan和您给出了类似的例子,证明使用unsigned在这里甚至更糟。就像您所说的,重要的是类型而不是值。如果rand是无符号的,我肯定不会做减法。这是通过小心避免的事情。当使用std::uniform_int_distribution<unsigend int>时也可能存在相同的问题。如果我有什么错误,请纠正我。 - Nimrod
5
@Nimrod,当您使用std::uniform_int_distribution<unsigned int>时,您明确要求unsigned。小心谨慎并不是避免错误的最佳解决方案。 size()是一个很好的例子。 当container为空时,for (int i = container.size()-1; i>=0; --i)看起来是正确的,但实际上它不是(循环将会出错)。作者在使用size()-1时未明确要求unsigned,但这就是他们得到的结果。 - 463035818_is_not_a_number
3
Java没有任何无符号整数类型。然而,Java的char类型是一个16位的无符号类型。 - Bathsheba
3
@Bathsheba 为什么这样呢?我相信Java的char类型代表UTF-16代码单元,因此必须是无符号的。 - Paul Sanders
4
@Bathsheba:Java中的char不适合用于算术运算。 - Ben Voigt
显示剩余9条评论

10

斯特鲁普在《C++程序设计语言》第6.2.4节中写道:
* 无符号整数类型非常适合将存储视为位数组的用途。使用无符号而不是int表示正整数以获取一个更多的比特位,几乎从来都不是一个好主意。通过将变量声明为无符号以确保某些值为正数的尝试通常会被隐式转换规则所打败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接