20

如果不需要额外的值范围,是否应该将变量声明为无符号整数?例如,在 for 循环中声明变量时,如果您知道它不会是负数,这有关系吗?一个比另一个快吗?像 C++ 中的 unsigned 一样声明 unsigned int 是不是很糟糕?

重申一下,即使不需要额外的范围也应该这样做吗?我听说应该避免使用它们,因为它们会引起混淆(IIRC 这就是 Java 没有它们的原因)。

4

7 回答 7

14

当无符号整数具有负值没有意义时,您应该使用它们。这完全独立于范围问题。所以是的,即使不需要额外的范围,你也应该使用无符号整数类型,不,如果没有必要,你不应该使用unsigned ints (或其他任何东西),但是你需要修改你对什么是必要的定义。

于 2012-09-01T06:40:59.697 回答
13

使用 uints 的原因是它为编译器提供了更广泛的优化。例如,如果它知道 x 是正数,它可以用 'x' 替换 'abs(x)' 的实例。它还开辟了各种仅适用于正数的按位“强度减少”。如果您总是将一个 int 乘以/除以 2 的幂,那么编译器可能会用位移(即 x*8 == x<<3)替换该操作,这往往会执行得更快。不幸的是,这种关系仅在“x”为正时才成立,因为负数的编码方式排除了这种情况。对于整数,如果编译器可以证明该值始终为正(或者可以在代码中更早地修改为正),则编译器可能会应用此技巧。在 uints 的情况下,这个属性很容易证明,

另一个例子可能是方程y = 16 * x + 12。如果 x 可以为负数,则需要进行乘法和加法。然而,如果 x 总是正数,那么不仅 x*16 项可以用 x<<4 代替,而且由于该项总是以四个零结尾,这就打开了用二进制 OR 代替“+ 12”(只要因为“12”项小于 16)。结果将是y = (x<<4) | 12

通常,“无符号”限定符为编译器提供了有关变量的更多信息,这反过来又允许它进行更多优化。

于 2012-09-01T07:05:34.773 回答
9

通常,您应该使用无符号整数。

就溢出等未定义的行为而言,它们更具可预测性。
这本身就是一个很大的话题,所以我不会多说。
除非您确实需要有符号值,否则避免使用有符号整数是一个很好的理由。

此外,它们在检查范围时更容易使用——您不必检查负值。

典型的经验法则:

  • 如果您正在编写一个将索引作为控制变量的正向for循环,您几乎总是需要无符号整数。事实上,你几乎总是想要.size_t

  • 如果您正在编写一个for将索引作为控制变量的反向循环,出于显而易见的原因,您可能应该使用有符号整数。应该ptrdiff_t会吧。

需要注意的一件事是在不同大小的有符号和无符号值之间进行转换时。
您可能需要仔细检查(或三次检查)以确保演员按您期望的方式工作。

于 2012-09-01T07:05:46.383 回答
7

int是通用整数类型。如果您需要一个整数,并且int满足您的要求(范围 [-32767,32767]),请使用它。

如果你有更专业的目的,那么你可以选择别的东西。如果您需要对数组的索引,请使用size_t. 如果您需要向量的索引,请使用std::vector<T>::size_type. 如果您需要特定尺寸,请从<cstdint>. 如果您需要大于 64 位的内容,请查找gmp 之类的库。

我想不出任何好的理由来使用unsigned int. 至少,不是直接的(size_t并且某些特定大小的类型<cstdint>可能是 typedef 的unsigned int)。

于 2012-09-01T07:53:44.863 回答
6

系统使用unsignedwhen 值不能为负的问题不是 Java 没有unsigned,而是带有无符号值的表达式,尤其是与有符号值混合时,如果您将无符号视为具有移位范围的整数类型。无符号是一种模块化类型,而不是将整数限制为正数或零。

unsigned因此,当您需要模块化类型或按位操作时,应该使用传统的观点。这种观点在 K&R 中是隐含的——看看 int 和 unsigned 是如何使用的——在 TC++PL(第 2 版,第 50 页)中更明确:

unsigned整数类型非常适合将存储视为位数组的用途。使用 anunsigned而不是 anint来获得更多位来表示正整数几乎从来都不是一个好主意。通过声明变量来确保某些值是正数的尝试unsigned通常会被隐式转换规则所挫败。

于 2012-09-01T08:48:41.113 回答
2

在几乎所有架构中,有符号操作和无符号操作的成本是相同的。因此,在效率方面,您不会因使用无符号签名而获得任何优势。但是正如您所指出的,如果您使用 unsigned 您将拥有更大的范围

于 2012-09-01T06:45:42.657 回答
1

即使您的变量只应采用非负值 unsigned 也可能是一个问题。这是一个例子。假设要求程序员编写代码来打印所有整数对 (a,b),其中 0 <= a < b <= n 其中 n 是给定的输入。不正确的代码是

for (unsigned b = 0; b <= n; b++)
   for (unsigned a=0; a <=b-1; b++)
       cout << a << ',' << b << n ;

这很容易纠正,但是用 unsigned 思考比用 int 思考要自然一些。

于 2015-12-03T14:43:55.327 回答