为啥 Array.Length 是一个 int,而不是一个 uint [重复]

Posted

技术标签:

【中文标题】为啥 Array.Length 是一个 int,而不是一个 uint [重复]【英文标题】:Why is Array.Length an int, and not an uint [duplicate]为什么 Array.Length 是一个 int,而不是一个 uint [重复] 【发布时间】:2010-09-05 14:22:23 【问题描述】:

为什么 Array.Length 是 int,而不是 uint。这让我很困扰(只是有点),因为长度值永远不会是负数。

这也迫使我在自己的班级中使用 int 作为长度属性,因为当你 指定一个 int 值,这需要显式转换...

所以最终的问题是:unsigned int (uint) 有什么用处吗?甚至微软似乎也没有使用它们。

【问题讨论】:

尽管有以下问题,我认为应该改为 UInt。 @alan2here 做出这样的改变会破坏几乎所有的代码,所以如果你问我就不会发生! 【参考方案1】:

Unsigned int 不符合 CLS,因此会将属性的使用限制为那些实现 UInt 的语言。

看这里:

框架 1.1

Introduction to the .NET Framework Class Library

框架 2.0

.NET Framework Class Library Overview

【讨论】:

【参考方案2】:

很多原因:

uint 不符合 CLS,因此依赖于它的内置类型(数组)会出现问题 最初设计的运行时禁止堆上的任何对象占用超过 2GB 的内存。由于小于或等于此限制的最大数组将是 new byte[int.MaxValue] ,因此能够生成正数但非法的数组长度会让人们感到困惑。 请注意,此限制为 somewhat removed in the 4.5 release,但仍保留标准 Length as int。 从历史上看,C# 的大部分语法和约定都继承自 C 和 C++。在这些数组中只是简单的指针运算,因此负数组索引是可能的(尽管通常是非法和危险的)。由于许多现有代码假定数组索引已签名,这将是一个因素 在相关说明中,在 C/C++ 中将有符号整数用于数组索引意味着与这些语言和非托管函数的互操作无论如何都需要在这些情况下使用 int,这可能会由于不一致而造成混淆。 BinarySearch 实现(许多算法中非常有用的组件)依赖于能够使用 int 的负值范围来指示未找到该值该值所在的位置应插入以保持排序。 在对数组进行操作时,您可能希望对现有索引进行负偏移。如果您使用了一个偏移量,它将使您使用 unit 超出数组的开头,那么环绕行为将使您的索引可能合法(因为它是正数)。使用 int 结果将是非法的(但安全,因为运行时会防止读取无效内存)

【讨论】:

如果堆上没有任何东西可以超过 2Gb,那么几乎所有长度为 int.MaxValue 的数组都是非法的,因为大多数类型都大于 1 字节。 确实如此,但 ((uint)(int.MaxValue)) + 1 对于任何东西都会保证是错误的。 int 本身远非完美,但事物的平衡使得保持 int 作为类型是合法的。 从一个明确的 ArrayIndex 类型(本质上是 size_t)开始,它可以根据需要干净、安全地转换为 int 可能会使将来更容易真正使用,允许在未来使用 > 2GB 数组少痛苦。但是语用学说java也有同样的问题,为什么要冒险 这是非常有用的。从 .NET 4.0 开始,在 Windows Communication Foundation 中,maxArrayLengthmaxBytesPerRead 的最大值为 2,147,483,647,回顾起来,这对这些信息很有意义。连接点... 只想在不安全的上下文中添加 C# 指针算法也允许负索引。请参阅此处的示例:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…【参考方案3】:

我认为这也可能与在较低级别上简化事情有关,因为如果 Array.Length 是无符号的,Array.Length 当然会在某个时候添加到负数,并添加到负 int (二进制补码),结果可能会很混乱。

【讨论】:

请举个例子? uint lenght = 3;int x = -4;Console.WriteLine(x+lenght); 产生 -1 就好了。【参考方案4】:

似乎没有人提供“终极问题”的答案。

我相信无符号整数的主要用途是提供与外部系统(P/Invoke 等)的更轻松接口,并满足移植到 .NET 的各种语言的需求。

【讨论】:

在连接多个较小的值以产生较大的值时,无符号类型是必不可少的。可以通过计算(HighPart << 16) + LowPart 将两个UInt16 组合成一个UInt32,也可以通过(Uint16)(Value >> 16)(Uint16)(Value & 65535) 将一个UInt32 拆分为两个UInt16。如果LowPart 必须是有符号类型,这样的操作会非常不方便。话虽如此,有符号和无符号类型之间的交互通常是令人困惑和有问题的。无符号类型在许多方面都应该被视为自己的世界。【参考方案5】:

通常,整数值是有符号的,除非您明确需要无符号值。这只是它们的使用方式。我可能不同意这个选择,但事实就是如此。

目前,由于当今典型的内存限制,如果您的数组或类似数据结构需要 UInt32 长度,您应该考虑其他数据结构。

使用字节数组,Int32 将为您提供 2GB 的值

【讨论】:

"但事实就是如此。" ——不,事情永远不会像现在这样。总会有一个设计决策,问为什么总是值得的。人们可能会从利弊中学到一些东西,或者让设计师(在某些情况下)参与关于它们的讨论。总是问问题! :)

以上是关于为啥 Array.Length 是一个 int,而不是一个 uint [重复]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 array[array.length] 返回未定义? [复制]

将int数组合并为单个int

返回值为int[] 的快排写法

数组中array==null和array.length==0的区别

将 int 数组合并为单个 int

array.length-=1 与 array.pop()