문제

I was just reading the C# specification and the part on array creation expressions. In the specification it says:

array-creation-expression:
new   non-array-type   [   expression-list ]   rank-specifiersopt   array-initializeropt
new   array-type   array-initializer
new   rank-specifier   array-initializer

[snip]

The dimension length expressions of the expression-list are evaluated in order, from left to right. Following evaluation of each expression, an implicit conversion (§6.1) to one of the following types is performed: int, uint, long, ulong. The first type in this list for which an implicit conversion exists is chosen. If evaluation of an expression or the subsequent implicit conversion causes an exception, then no further expressions are evaluated and no further steps are executed.

Excited, I thought hmm I don't think I've seen that yet, let's try a long dimension length:

bool[] bb = new bool[2L + Int32.MaxValue];
bb[int.MaxValue + 1L] = true;

Visual Studio says while pointing to the first line:

Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow.

Note this is NOT an "OutOfMemoryException". If I change my array creation expression and make it a little smaller:

bool[] bb = new bool[Int32.MaxValue];

This time I get an "OutOfMemoryException". I know about the whole "no object can be larger than 2GB" restriction from the CLR. My question is why am I getting a very different exception (OverflowException vs OutOfMemoryException) when the length is no longer convertible to Int32?

도움이 되었습니까?

해결책

The compiler can infer a larger integral type based upon the inputs to the dimensions calculation, but that does not mean the length of the array can exceed the limit. The compiler is basically converting the value to a native integer in a checked context, using an op code that will throw the overflow. This is to prevent the value from wrapping or otherwise allowing a negative number as the dimension.

As an example, note the array declaration here:

var array = new int[2L + int.MaxValue];

And the resultant IL

IL_0001:  ldc.i4      01 00 00 80 
IL_0006:  conv.u8     
IL_0007:  conv.ovf.i 
IL_0008:  newarr      System.Int32
IL_000D:  stloc.0     // array

Pay particular attention to the third line. That op code is the instruction to produce the conversion and throws the exception upon failure.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top