Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Array Internals

Internally, the CLR actually supports two different kinds of arrays:

 

■ Single-dimensional arrays with a lower bound of 0. These arrays are sometimes called SZ (for single-dimensional, zero-based) arrays or vectors.

■ Single-dimensional and multi-dimensional arrays with an unknown lower bound.

 

You can actually see the different kinds of arrays by executing the following code (the output is shown in the code’s comments).

 

using System;

 

public sealed class Program { public static void Main() { Array a;

 

// Create a 1­dim, 0­based array, with no elements in it a = new String[0];

Console.WriteLine(a.GetType()); // "System.String[]"

 

// Create a 1­dim, 0­based array, with no elements in it a = Array.CreateInstance(typeof(String),

new Int32[] { 0 }, new Int32[] { 0 }); Console.WriteLine(a.GetType()); // "System.String[]"

 

// Create a 1­dim, 1­based array, with no elements in it a = Array.CreateInstance(typeof(String),

new Int32[] { 0 }, new Int32[] { 1 });

Console.WriteLine(a.GetType()); // "System.String[*]" <­­ INTERESTING! Console.WriteLine();


// Create a 2­dim, 0­based array, with no elements in it a = new String[0, 0];

Console.WriteLine(a.GetType()); // "System.String[,]"

 

// Create a 2­dim, 0­based array, with no elements in it a = Array.CreateInstance(typeof(String),

new Int32[] { 0, 0 }, new Int32[] { 0, 0 }); Console.WriteLine(a.GetType()); // "System.String[,]"

 

// Create a 2­dim, 1­based array, with no elements in it a = Array.CreateInstance(typeof(String),

new Int32[] { 0, 0 }, new Int32[] { 1, 1 }); Console.WriteLine(a.GetType()); // "System.String[,]"

}

}

 

Next to each Console.WriteLine is a comment that indicates the output. For the single- dimensional arrays, the zero-based arrays display a type name of System.String[], whereas the 1-based array displays a type name of System.String[*]. The * indicates that the CLR knows that this array is not zero-based. Note that C# does not allow you to declare a variable of type String[*], and therefore it is not possible to use C# syntax to access a single-dimensional, non-zero–based array. Although you can call Array’s GetValue and SetValue methods to ac- cess the elements of the array, this access will be slow due to the overhead of the method call.

For multi-dimensional arrays, the zero-based and 1-based arrays all display the same type name: System.String[,]. The CLR treats all multi-dimensional arrays as though they are not zero-based at run time. This would make you think that the type name should display as System.String[*,*]; however, the CLR doesn’t use the *s for multi-dimensional arrays because they would always be pres- ent, and the asterisks would just confuse most developers.

Accessing the elements of a single-dimensional, zero-based array is slightly faster than accessing the elements of a non-zero–based, single-dimensional array or a multi-dimensional array. There are several reasons for this. First, there are specific IL instructions—such as newarr, ldelem, ldelema, ldlen, and stelem—to manipulate single-dimensional, zero-based arrays, and these special IL in- structions cause the JIT compiler to emit optimized code. For example, the JIT compiler will emit code that assumes that the array is zero-based, and this means that an offset doesn’t have to be subtracted from the specified index when accessing an element. Second, in common situations, the JIT compiler is able to hoist the index range–checking code out of the loop, causing it to execute just once. For example, look at the following commonly written code.



 

using System;

 

public static class Program { public static void Main() {

Int32[] a = new Int32[5];

for(Int32 index = 0; index < a.Length; index++) {

// Do something with a[index]

}

}

}


The first thing to notice about this code is the call to the array’s Length property in the for loop’s test expression. Because Length is a property, querying the length actually represents a method call. However, the JIT compiler knows that Length is a property on the Array class, and the JIT compiler will actually generate code that calls the property just once and stores the result in a temporary vari- able that will be checked with each iteration of the loop. The result is that the JITted code is fast. In fact, some developers have underestimated the abilities of the JIT compiler and have tried to write “clever code” in an attempt to help the JIT compiler. However, any clever attempts that you come

up with will almost certainly impact performance negatively and make your code harder to read, reducing its maintainability. You are better off leaving the call to the array’s Length property in the preceding code instead of attempting to cache it in a local variable yourself.

The second thing to notice about the preceding code is that the JIT compiler knows that the for loop is accessing array elements 0 through Length ­ 1. So the JIT compiler produces code that, at run time, tests that all array accesses will be within the array’s valid range. Specifically, the JIT compiler produces code to check if (0 >= a.GetLowerBound(0)) && ((Length – 1)

<= a.GetUpperBound(0)). This check occurs just before the loop. If the check is good, the JIT compiler will not generate code inside the loop to verify that each array access is within the valid range. This allows array access within the loop to be very fast.

Unfortunately, as I alluded to earlier in this chapter, accessing elements of a non-zero–based sin- gle-dimensional array or of a multi-dimensional array is much slower than a single-dimensional, zero- based array. For these array types, the JIT compiler doesn’t hoist index checking outside of loops, so each array access validates the specified indexes. In addition, the JIT compiler adds code to subtract the array’s lower bounds from the specified index, which also slows the code down, even if you’re us- ing a multi-dimensional array that happens to be zero-based. So if performance is a concern to you, you might want to consider using an array of arrays (a jagged array) instead of a rectangular array.

C# and the CLR also allow you to access an array by using unsafe (non-verifiable) code, which is, in effect, a technique that allows you to turn off the index bounds checking when accessing an array. Note that this unsafe array manipulation technique is usable with arrays whose elements are SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Single, Double, Decimal, Boolean, an enumerated type, or a value type structure whose fields are any of the aforementioned types.

This is a very powerful feature that should be used with extreme caution because it allows you to perform direct memory accesses. If these memory accesses are outside the bounds of the array, an exception will not be thrown; instead, you will be corrupting memory, violating type safety, and pos- sibly opening a security hole! For this reason, the assembly containing the unsafe code must either be granted full trust or at least have the Security Permission with Skip Verification turned on.

The following C# code demonstrates three techniques (safe, jagged, and unsafe), for accessing a two-dimensional array.

 

using System;

using System.Diagnostics;

 

public static class Program {

private const Int32 c_numElements = 10000;


public static void Main() {

// Declare a two­dimensional array

Int32[,] a2Dim = new Int32[c_numElements, c_numElements];

 

// Declare a two­dimensional array as a jagged array (a vector of vectors) Int32[][] aJagged = new Int32[c_numElements][];

for (Int32 x = 0; x < c_numElements; x++) aJagged[x] = new Int32[c_numElements];

 

// 1: Access all elements of the array using the usual, safe technique Safe2DimArrayAccess(a2Dim);

 

// 2: Access all elements of the array using the jagged array technique SafeJaggedArrayAccess(aJagged);

 

// 3: Access all elements of the array using the unsafe technique Unsafe2DimArrayAccess(a2Dim);

}

 

private static Int32 Safe2DimArrayAccess(Int32[,] a) { Int32 sum = 0;

for (Int32 x = 0; x < c_numElements; x++) { for (Int32 y = 0; y < c_numElements; y++) {

sum += a[x, y];

}

}

return sum;

}

 

private static Int32 SafeJaggedArrayAccess(Int32[][] a) { Int32 sum = 0;

for (Int32 x = 0; x < c_numElements; x++) { for (Int32 y = 0; y < c_numElements; y++) {

sum += a[x][y];

}

}

return sum;

}

 

private static unsafe Int32 Unsafe2DimArrayAccess(Int32[,] a) { Int32 sum = 0;

fixed (Int32* pi = a) {

for (Int32 x = 0; x < c_numElements; x++) { Int32 baseOfDim = x * c_numElements;

for (Int32 y = 0; y < c_numElements; y++) { sum += pi[baseOfDim + y];

}

}

}

return sum;

}

}


The Unsafe2DimArrayAccess method is marked with the unsafe modifier, which is required to use C#’s fixed statement. To compile this code, you’ll have to specify the /unsafe switch when invoking the C# compiler or select the Allow Unsafe Code check box on the Build tab of the Project Properties pane in Microsoft Visual Studio.

Obviously, the unsafe technique has a time and place when it can best be used by your own code, but beware that there are three serious downsides to using this technique:

■ The code that manipulates the array elements is more complicated to read and write than that which manipulates the elements using the other techniques because you are using C#’s fixed statement and performing memory-address calculations.

■ If you make a mistake in the calculation, you are accessing memory that is not part of the ar- ray. This can result in an incorrect calculation, corruption of memory, a type-safety violation, and a potential security hole.

■ Due to the potential problems, the CLR forbids unsafe code from running in reduced-security environments (like Microsoft Silverlight).

 

 


Date: 2016-03-03; view: 658


<== previous page | next page ==>
Nbsp;   All Arrays Implicitly Implement IEnumerable, ICollection, and IList | Nbsp;   Unsafe Array Access and Fixed-Size Array
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.008 sec.)