我到处都使用unsigned int,但不确定是否应该这样做。可以是从数据库主键ID列到计数器等。如果数字永远不能为负,那么我将始终使用无符号整数。
但是我从其他人的代码中注意到,似乎没有其他人可以这样做。我忽略了一些关键的事情吗?
编辑:由于这个问题,我也注意到在C语言中,返回错误的负值是司空见惯的,而不是像C ++中那样引发异常。
我到处都使用unsigned int,但不确定是否应该这样做。可以是从数据库主键ID列到计数器等。如果数字永远不能为负,那么我将始终使用无符号整数。
但是我从其他人的代码中注意到,似乎没有其他人可以这样做。我忽略了一些关键的事情吗?
编辑:由于这个问题,我也注意到在C语言中,返回错误的负值是司空见惯的,而不是像C ++中那样引发异常。
Answers:
int
不会造成这种困难(但是,因为任何计算都会提升为int
);关于缺少无符号字节类型,我没有什么好说的。
我认为Michael是有道理的,但是IMO之所以每个人都一直使用int的原因(尤其是在中for (int i = 0; i < max, i++
)是因为我们是这样学习的。当“ 如何学习编程 ”书中的每个示例都循环使用int
时for
,很少有人会质疑这种做法。
另一个原因是int
比短25%uint
,我们都很懒... ;-)
++
在增加时使用后缀的原因,尽管事实上很少需要它的特殊行为,如果循环索引是迭代器或其他非基本类型(或者编译器确实很密集),甚至可能导致毫无意义地复制副本。 。
将范围信息编码为类型是一件好事。它在编译时强制使用合理的数字。
许多体系结构似乎都有专门的指令来处理int
-> float
转换。的转换unsigned
可能会比较慢(一点点)。
对我而言,沟通非常重要。通过显式使用unsigned int,您可以告诉我带符号的值不是有效值。这使我在读取代码时除了变量名外还可以添加一些信息。理想情况下,我可以使用非匿名类型告诉我更多信息,但是,与在各处都使用int相比,它可以为我提供更多信息。
不幸的是,并不是每个人都非常了解他们的代码所传达的内容,这也许就是即使值至少是无符号的,您仍然在各处看到整数的原因。
我unsigned int
在C ++中主要用于数组索引,以及用于任何从0开始的计数器。我认为最好明确地说“此变量不能为负数”。
在处理实际上可能接近或超过有符号int限制的整数时,您应该注意这一点。由于32位整数的正最大值为2,147,483,647,因此,如果您知道a)永不为负,并且b)可能达到2,147,483,648,则应使用无符号整数。在大多数情况下,包括数据库密钥和计数器,我什至都不会处理这些数字,因此我不必担心自己是否担心符号位用于数字值或指示符号。
我会说:使用int,除非您知道需要一个unsigned int。
我倾向于同意乔尔·埃瑟顿的推理,但得出相反的结论。我的看法是,即使您知道数字不太可能接近带符号类型的限制,如果您知道不会出现负数,那么使用类型的带符号变体的理由就很少了。
出于同样的原因,为什么在少数选择的实例中,在SQL Server表中使用BIGINT
(64位整数)而不是INTEGER
(32位整数)。数据在任何合理的时间内达到32位限制的可能性很小,但是,如果发生这种情况,则在某些情况下的后果可能是毁灭性的。只需确保在各种语言之间正确映射类型,否则您将最终产生有趣的怪异...
就是说,对于某些事情,例如数据库主键值,带符号或无符号确实没有关系,因为除非您手动修复损坏的数据或类似的东西,否则您将永远不会直接处理该值。这是一个标识符,仅此而已。在这些情况下,一致性可能比正确选择签名更为重要。否则,您最终将获得一些带符号的外键列,而另一些则是无符号的外键列,没有明显的样式-或再次是有趣的怪异。
我建议在空间受限的外部数据存储和数据交换上下文中,通常应使用带符号的类型。在大多数情况下,今天32位有符号整数太小而32位无符号值就足够了,不久之后32位无符号值也不会足够大。
人们应该使用无符号类型的主要时间是将多个值组合为一个较大的值(例如,将四个字节转换为一个32位数字),或者将较大的值分解为较小的值(例如,将32位数字存储为四个字节)。 ),或者需要定期处理的数量(例如住宅用电表;其中大多数都有足够的数字以确保在读数之间不会发生翻滚) (如果一年读取三遍,但不足以确保它们不会在电表的使用寿命内滚动)。无符号类型通常具有足够的“怪异性”,因此仅在需要其语义的情况下才应使用它们。
size_t
签名并ptrdiff_t
签名的原因是有原因的。
我使用无符号整数使我的代码及其意图更加清楚。在对有符号和无符号类型进行算术运算时,为防止意外的隐式转换,我要做的一件事是对我的无符号变量使用无符号短型(通常为2个字节)。这是有效的,原因有两个:
一般原则是,无符号变量的类型应比有符号变量的类型具有较低的等级,以确保提升为有符号类型。这样就不会有任何意外的溢出行为。显然,您不能一直确保这一点,但是(大多数)通常可以确保这一点。
例如,最近我有一些for循环,如下所示:
const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
if((i-2)%cuint == 0)
{
//Do something
}
}
文字“ 2”的类型为int。如果i是无符号int而不是无符号short,则在子表达式(i-2)中,2将被提升为无符号int(因为unsigned int的优先级高于signed int)。如果i = 0,则子表达式等于(0u-2u)=由于溢出而产生的较大值。i = 1时的想法相同。但是,由于i是一个无符号的short,因此它被提升为与文字'2'相同的类型,后者的符号为int,并且一切正常。
为了增加安全性:在极少数情况下,您要在其上实现的体系结构将int设为2个字节,这可能会导致在无符号short变量不合适的情况下,将算术表达式中的两个操作数都提升为unsigned int到带符号的2字节int中,后者的最大值为32,767 <65,535。(有关更多详细信息,请参见https://stackoverflow.com/questions/17832815/c-implicit-conversion-signed-unsigned)。为了防止这种情况,您可以简单地在程序中添加static_assert,如下所示:
static_assert(sizeof(int) == 4, "int must be 4 bytes");
并且不会在int为2个字节的体系结构上进行编译。
for(unsigned int n = 10; n >= 0; n --)
(无限循环)