对于表示长度或计数变量,使用有符号整数还是无符号整数更好?
在我看来,C++ STL 倾向于喜欢unsigned ( std::size_t
,就像在std::vector::size()中一样,而不是 C# BCL倾向于喜欢有符号整数(就像在ICollection.Count中一样。
考虑到长度或计数是非负整数,我的直觉会选择unsigned;但我不明白为什么.NET 设计者选择有符号整数。
最好的方法是什么?各有什么优缺点?
对于表示长度或计数变量,使用有符号整数还是无符号整数更好?
在我看来,C++ STL 倾向于喜欢unsigned ( std::size_t
,就像在std::vector::size()中一样,而不是 C# BCL倾向于喜欢有符号整数(就像在ICollection.Count中一样。
考虑到长度或计数是非负整数,我的直觉会选择unsigned;但我不明白为什么.NET 设计者选择有符号整数。
最好的方法是什么?各有什么优缺点?
C++ 使用无符号值,因为它们需要完整的范围。在 32 位系统上,该语言应该能够拥有 4 GB 的向量,而不仅仅是 2 GB 的向量。(操作系统可能不允许您使用全部 4 GB,但语言本身不想妨碍您)
在 .NET 中,无符号整数不符合 CLS。您可以使用它们(在某些 .NET 语言中),但它限制了可移植性和兼容性。所以对于基类库,它们只使用有符号整数。
然而,这些都是边缘情况。对于大多数用途来说,一个有符号int
的就足够大了。因此,只要两者都提供您需要的范围,您就可以同时使用两者。
有符号整数有时具有的一个优点是它们更容易检测下溢。假设您正在计算一个数组索引,并且由于一些错误的输入,或者您的程序中可能存在逻辑错误,您最终尝试访问 index -1
。
使用有符号整数,很容易检测到。使用 unsigned 时,它将环绕并变为UINT_MAX
. 这使得检测错误变得更加困难,因为您期望一个正数,而您得到了一个正数。
所以真的,这取决于。C++ 使用无符号,因为它需要范围。.NET 使用签名是因为它需要使用没有未签名的语言。
在大多数情况下,两者都可以工作,有时,签名可以使您的代码更可靠地检测错误。
将无符号类型用于计数和大小是很自然的,除非我们在某些上下文中它们可能是负数但有意义。我的猜测是 C++ 遵循它的哥哥 C 的相同逻辑,其中strlen()
returnsize_t
和malloc()
take size_t
。
C++(和C)中带有符号和无符号整数的问题是,当您混合使用这两种整数时,您必须知道它们是如何相互转换的。一些人主张对所有整数都使用有符号整数,以避免程序员无知和疏忽的问题。但我认为程序员必须知道如何使用他们的交易工具(编程语言、编译器等)。迟早他们会被转换所咬,如果不是他们所写的,那么其他人所拥有的。这是不可避免的。
因此,了解您的工具,选择适合您情况的工具。
这里有几个方面:
1)最大值:通常有符号数的最大值是对应无符号最大值的1/2。例如,在 C 中,最大有符号短值是 32767,而最大无符号短值是 65535(因为 -ve 数字不需要范围的 1/2)。因此,如果您期望的长度或计数会很大,那么无符号表示会更有意义。
2) 安全性:您可以浏览网络查找整数溢出错误,但可以想象以下代码:
if (length <= 100)
{
// do something with file
}
...然后,如果“长度”是一个有符号值,那么您将冒“长度”是一个 -ve 数字的风险(尽管是恶意的,一些强制转换等)并且代码没有执行您所期望的。我在以前的项目中看到过这个,其中每个事务都会增加一个序列,但是当我们使用的有符号整数达到最大有符号整数值(2147483647)时,它在下一个增量之后突然变成 -ve 并且我们的代码无法处理它。
无论底层语言/API考虑如何,都需要考虑一些事情。
如果您不设计可重用的库(在 .NET 术语中,例如 VB.NET 项目使用您的 C# 类库),那么选择适合您的。当然,如果您正在创建任何类型的 DLL,并且您的库可以在具有不同语言的项目中使用是可行的(再次想到 VB.NET),那么您需要注意不兼容的类型(无符号)。