unsigned
整数有一些奇怪的属性,你应该避免它们,除非你有一个很好的理由。获得1额外的积极大小,或表示限制,价值可能不是负面的,是不是很好的理由。
unsigned
整数算术实现模UINT_MAX+1
。相比之下,signed
整数的操作代表了我们从学校中熟悉的自然算术。
溢出语义
unsigned
已明确定义的溢出; signed
不会:
unsigned u = UINT_MAX;
u++; // u becomes 0
int i = INT_MAX;
i++; // undefined behaviour
这有符号整数溢出测试过程中被抓,而一个无符号的溢出,会默默地做错事的后果。因此,只有在确定要合法化溢出时才使用unsigned
。
如果你有一个约束条件,一个值可能不是负数,那么你需要一种方法来检测和拒绝负值; int
是完美的。一个unsigned
将接受一个负值,并默默地将其溢出为正值。的量不大于所述数据类型的位的数目更大的unsigned
位移语义
位移总是很好的定义。 signed
的位移是不确定的,如果它会导致符号位中的1左移,或者实现定义是否会导致符号位中的1右移。因此,使用unsigned
进行某些类型的旋转操作。
混合符号运算
内置的算术运算总是在同一类型的操作数。如果他们提供的不同类型的操作数,“通常的算术转换”强迫他们将同种类型,有时令人惊讶的结果:
unsigned u = 42;
std::cout << (u * -1); // 4294967254
std::cout << std::boolalpha << (u >= -1); // false
有什么区别?
减去另一个unsigned
一个unsigned
产生一个unsigned
结果,这意味着2
和1
之间的差4294967295
。
双最大值
int
使用一个位来表示值的符号。 unsigned
将此位用作另一个数字位。所以通常,int
有31位数字,而unsigned
有32位。这个额外位通常被引用为使用unsigned
的理由。但是,如果31位对于特定目的不够用,则最有可能的32位也将不足,并且应该考虑64位或更多位。
函数重载
从int
到unsigned
的隐式转换具有相同的秩从int
到double
转换,所以下面的例子是病态形成:
void f(unsigned);
void f(double);
f(42); // error: ambiguous call to overloaded function
互操作性
许多API(包括标准库)使用unsigned
类型,通常是出于错误的原因。在与这些API进行交互时,使用unsigned
以避免混合签名操作是明智的。
附录
所引用的片段包括表达0 <= grade <= 100
。这将首先评估0 <= grade
,总是true
,因为grade
不能为负数。然后它将评估true <= 100
,其总是true
,因为true
被转换为整数1
,并且1 <= 100
是true
。
问问原作者的代码。在我看来,这里没有理由使用'unsigned'。 – MikeMB
@MikeMB分数和分数是否为负?如果他们不能,那么他们应该没有签名。特别是,看起来成绩被用作数组索引,所以它可能必须是积极的。我的建议是将未签名,如果你现在的负值是没有意义的 –
Off topic:'cin >> grade''cin'太愚蠢,无法正确做到这一点。输入-1并查看“成绩”结果。 – user4581301