为什么初始化负大小的数组会导致溢出异常?

ADA*_*MJR 5 c# integer-overflow

我在 C# 中进行单元测试,发现以下代码给出了溢出异常:

using System;
                    
public class Program
{
    public static void Main()
    {
        int i = 0;
        Console.WriteLine(new float[i - 1]);
        // System.OverflowException: Arithmetic operation resulted in an overflow.
    }
}
Run Code Online (Sandbox Code Playgroud)

https://dotnetfiddle.net/clbgZ3

但是,如果您显式尝试初始化负数组,则会收到以下错误:

Console.WriteLine(new float[-1]);
// Compilation error: Cannot create an array with a negative size
Run Code Online (Sandbox Code Playgroud)

为什么初始化负大小的数组会导致溢出异常,而不是其他类型的错误?

Han*_*ing 7

这不是堆栈溢出,而是数字溢出:-1 超出了合法值(可能是无符号整数)。有关确切的语言规范,请参阅orhtej2的答案。

同样的异常也会发生:

int i = -1;
checked
{
    uint ui = (uint)i;
    // Arithmetic operation resulted in an overflow.
}
Run Code Online (Sandbox Code Playgroud)

您确实需要checked出现此错误的上下文,否则只会复制这些位(并且该值将为 4294967295)。

关于不同的错误:第一个是运行时异常,第二个是编译器错误。

  • 如果**有符号到无符号的转换发生在幕后,那么这是有意义的,另一方面,由于某种原因 [Ąrray.Length](https://learn.microsoft.com/en-us/dotnet/api/ system.array.length?view=net-7.0) 是有符号的 `int` 类型,所以我不确定是否会发生这种转换。我并不是说拥有一个长度为“-1”的数组是有意义的。 (2认同)
  • 我将“System.OverflowException”中的“System”误读为“Stack”,不要问我怎么理解的。这两个答案都内容丰富。Array.Length 确实使用有符号整数,但也许是为了防止在您想要按长度迭代数组时必须在 uint 和 int 之间显式转换。 (2认同)

orh*_*ej2 6

此行为在 C# 语言规范第 12.8.16.5节中明确指定

数组创建表达式的求值结果被归类为值,即对新分配的数组实例的引用。数组创建表达式的运行时处理包括以下步骤:

(...)

  • 验证维度长度的计算值,如下所示:如果一个或多个值小于零, System.OverflowException则抛出 a 并且不执行进一步的步骤。

(强调我的)

  • 有趣的是,指定它会引发误导性错误,但是 [`Array.CreateInstance`](https://learn.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=net-7.0 #system-array-createinstance(system-type-system-int32)) 抛出更直观的“ArgumentOutOfRangeException”。 (3认同)