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

Nim*_*rod 31 c++ random

std::rand说,

\n
\n

int rand();
\n返回 \xe2\x80\x8b0\xe2\x80\x8b 和 RAND_MAX 之间的伪随机积分值(包括 \xe2\x80\x8b0\xe2\x80\x8b 和 RAND_MAX)。

\n
\n

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

\n

我不是在谈论我们是否应该在这里使用它。这是一个历史问题还是一些糟糕的设计?

\n

for*_*818 42

关于 的争论很多unsigned。在不过多涉及主观领域的情况下,请考虑以下事项:重要的不是返回的值rand()是否不能为负。重要的是rand()返回特定类型的值,并且该类型决定您可以对该值执行哪些操作。rand()永远不会返回负值,但是对值应用使该值变为负值的操作是否有意义?当然是的。例如,您可能想要执行以下操作:

 auto x = rand() % 6 - 3;
Run Code Online (Sandbox Code Playgroud)

如果rand()返回一个,unsigned那么这将导致看起来正常的代码中出现令人困惑的错误。

unsigned例如,用于指数则是另一回事。指数始终为正。如果您想对其应用将值变为负值的操作,那么它就不再是索引了。rand() % 6 -3另一方面是随机数,无论是正数还是负数。

类型超出了它可以表示的值的范围。有符号和无符号整数具有不同的语义。

请注意,C++20 引入了std::ssize. 它是容器的大小,只能是正值。尽管如此,还是签署了。这是正值的一个例子,这些正值只是为了允许有符号算术而被签名。此外,也不能选择更改std::size为返回签名,因为这会破坏现有代码。

顺便说一句,Java 根本没有无符号整数类型,因为无符号算术被认为太混乱了。

  • @Nimrod,当您使用“std::uniform_int_distribution<unsigned int>”时,您会特别要求无符号。小心并不是避免错误的最佳解决方案。`size()` 未签名就是一个很好的例子。`for (int i=container.size()-1; i>=0; --i)` 看起来正确,但事实并非如此(如果 `container` 为空,则循环将严重破坏)。作者在使用“size()-1”时没有明确要求 unsigned,但这就是他们得到的 (5认同)
  • @Bathsheba:Java `char` 不适合用于算术。 (4认同)
  • “Java 根本没有无符号整数类型”。唉,Java 的“char”是一个 16 位无符号类型。 (3认同)
  • @Bathsheba 为什么唉?我相信 Java 的 char 类型代表 UTF-16 代码单元,因此_需要_是无符号的。 (3认同)
  • 感谢您的回答。@Alan,你给出了一个类似的例子来证明使用 unsigned 在这里更糟糕。就像你说的,重要的是类型而不是值。如果 rand 没有签名,我绝对不会做减法。这是你可以通过小心避免的事情。使用“std::uniform_int_distribution<unsigend int>”时也可能出现相同的问题。如果我有什么不对的地方请纠正我。 (2认同)

小智 10

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