为什么要宣布“得分[11] = {};”和“等级”为“无符号”而不是“int”

时间:2016-02-24 06:56:30

标签: c++ arrays c++11 unsigned

我是C ++的新手,正在尝试学习数组的概念。我在网上看到了这段代码。对于下面的示例代码,声明是否有任何区别:

params['song'][:filename]

as:

id

我想必须有unsigned scores[11] = {}; unsigned grade; int scores[11] = {}; int grade; 声明为score[11] = {};的原因,但背后的原因是什么?

grade

5 个答案:

答案 0 :(得分:6)

unsigned表示variable不会保留负值(甚至更准确 - 它不会关心标志)。很明显,scoresgrades是无符号值(没有人得分-25)。因此,使用unsigned是很自然的。

但请注意:if (0 <= grade <= 100)是多余的。 if (grade <= 100)就足够了,因为不允许使用负值。

正如Blastfurnace评论的那样,if (0 <= grade <= 100)是不对的。如果你想这样,你应该把它写成:

if (0 <= grade && grade <= 100)

答案 1 :(得分:4)

无符号变量

将变量声明为unsigned int而不是int会产生两个后果:

  • 不能否定。它为您提供了永远不会保证的保证,因此在编写仅适用于正整数的代码时,您不需要检查它并处理特殊情况
  • 由于您的尺寸有限,它可以让您代表更大的数字。在32位上,最大unsigned int为4294967295(2 ^ 32-1),而最大int为2147483647(2 ^ 31-1)

使用unsigned int的一个结果是算术将在unsigned int的集合中完成。所以9 - 10 = 4294967295而不是-1,因为unsigned int类型不能编码负数。如果将它们与否定int进行比较,您也会遇到问题。

More info on how negative integer are encoded.

数组初始化

对于数组定义,如果你只写:

unsigned int scores[11];

然后你有11个未初始化的unsigned int,其潜在值不同于0。

如果你写:

unsigned int scores[11] = {};

然后使用默认值0来初始化所有int。

请注意,如果你写:

unsigned int scores[11] = { 1, 2 };

你将第一个int初始化为1,第二个为2,其他所有为0。

您可以轻松地使用所有这些语法来进一步了解它。

<强>比较

关于代码:

if(0 <= grade <= 100)

如评论中所述,这并不符合您的期望。实际上,这将始终评估为true,因此在if中执行代码。这意味着如果您输入的等级为20000,则应该有一个核心转储。原因是:

0 <= grade <= 100

相当于:

(0 <= grade) <= 100

第一部分是true(隐式转换为1)或false(隐式转换为0)。由于两个值均低于100,因此第二个比较始终为true

答案 2 :(得分:3)

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结果,这意味着21之间的差异为4294967295

加倍最大值

int使用一位来表示值的符号。 unsigned使用此位作为另一个数字位。通常情况下,int有31个数字位,unsigned有32个。这个额外的位通常被引用为使用unsigned的理由。但如果31位不足以满足特定目的,那么很可能32位也不够,你应该考虑64位或更多位。

功能重载

intunsigned的隐式转换与从intdouble的转换具有相同的排名,因此以下示例生成错误:

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转换为整数11 <= 100true。< / p>

答案 3 :(得分:2)

是的确有所作为。在第一种情况下,您声明一个包含11个元素的数组,类型为&#34; unsigned int&#34;的变量。在第二种情况下,您将它们声明为整数。

当int为32位时,您可以使用以下范围中的值

-2,147,483,648至2,147,483,647 for plain int

无符号整数

0到4,294,967,295

当你不需要负号时,你通常会声明一些未签名的东西,你需要无符号给出的额外范围。在您的情况下,我假设通过声明未签名的变量,开发人员不接受负分数和分数。您基本上可以统计在命令行中引入了0到10之间的等级。所以它看起来像模拟学校评分系统,因此你没有负面成绩。但阅读完代码后,这是我的意见。

看一下这篇解释unsigned是什么的帖子:

what is the unsigned datatype?

答案 4 :(得分:2)

顾名思义,有符号整数可以是负数,也可以是无符号整数。如果我们表示具有N位的整数,则对于无符号,最小值为0并且最大值为2 ^(N-1)。如果它是N比特的有符号整数,那么它可以取-2 ^(N-2)到2 ^(N-2)-1的值。这是因为我们需要1位来表示符号+/-

Ex:签名的3位整数(是的,有这样的东西)

000 = 0
001 = 1
010 = 2
011 = 3
100 = -4
101 = -3
110 = -2
111 = -1

但是,对于无符号,它只代表值[0,7]。示例中的最高有效位(MSB)表示负值。也就是说,设置MSB的所有值都是负的。因此,它的绝对值明显损失了一点。

它也表现得像人们预期的那样。如果你增加-1(111),我们得到(1 000),但由于我们没有第四位,它只是#34;从结束时掉落&#34;我们留下了000.

同样适用于从0减去1.首先取两个补码

 111 = twos_complement(001) 

并将其添加到000,产生111 = -1(来自表格),这是人们可能期望的。增加011(= 3)产生100(= - 4)时会发生什么,这可能不是人们所期望的,与我们的正常预期不一致。这些溢出在定点运算中很麻烦,必须处理。

值得指出的另一件事是有符号整数可以取一个负值而不是正数,这会产生舍入的结果(例如,当使用整数表示定点数时)但是我确定这样做了更好地涵盖DSP或信号处理论坛。