【问题标题】:Why is the return type of std::rand() not an unsigned int?为什么 std::rand() 的返回类型不是无符号整数?
【发布时间】:2022-03-28 23:04:05
【问题描述】:

std::rand说,

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

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

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

【问题讨论】:

  • 可能是因为 int 在过去被认为是一流的类型。 (K&R C legacy ?)请注意,支持无符号类型的语言相对较少。
  • 如果 RAND_MAX 小于 2^31(通常更小),那么未签名没有任何好处,但如果有人这样做 rand() % 100 - 50 可能会得到令人惊讶的结果跨度>
  • 请注意,rand() 是一个非常古老的函数。在 C 标准化之前,它肯定就在这里。它可能是在将无符号整数添加到语言之前创建的。
  • 这是历史性的。 (记忆中)rand()/srand() 在 C 支持的无符号(或长!)类型之前指定。那时,大多数 C 实现都有 16 位的 int,只有少数有 32 位的 int,这就是为什么 RAND_MAX 只需要 32767(或更多)。当 Unix 用 C 重写时(1973 年),引入了无符号和长类型(除其他外)。 C 的后续演变(包括 C89 标准)保持向后兼容性,第一个 C++ 标准(根据 ARM)需要尽可能保持与 C89 的兼容性。

标签: c++ random


【解决方案1】:

关于unsigned 有很多争论。无需过多进入主观领域,请考虑以下事项:重要的不是从rand() 返回的值是否不能为负。重要的是rand() 返回一个特定类型的值,该类型决定了您可以使用该值做什么。 rand() 从不返回负值,但是对使值变为负的值应用操作是否有意义?当然可以。例如,您可能想要这样做:

 auto x = rand() % 6 - 3;

如果rand() 会返回unsigned,那么这会导致看起来没问题的代码中出现令人困惑的错误。

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

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

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

作为旁注,请考虑 Java 根本没有无符号整数类型,因为无符号算术被认为太混乱了。

【讨论】:

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

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

【讨论】:

    猜你喜欢
    • 2013-04-12
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    相关资源
    最近更新 更多