Net framework 5, а также среды Visual Studio 2012 и C#


Внутренняя реализация массивов



Download 6,27 Mb.
Pdf ko'rish
bet314/658
Sana12.06.2023
Hajmi6,27 Mb.
#950840
1   ...   310   311   312   313   314   315   316   317   ...   658
Bog'liq
CLR via C Programmirovanie na platforme Microsoft NET Framework 4 5 na yazyke C

Внутренняя реализация массивов
В CLR поддерживаются массивы двух типов:
‰
Одномерные массивы с нулевым начальным индексом. Иногда их называют 
SZ-массивами
(от английского single-dimensional, zero-based), или 
векторами
.
‰
Одномерные и многомерные массивы с неизвестным начальным индексом.
Рассмотрим их на примере следующего кода (результат его выполнения при-
водится в комментариях):
using System;
public sealed class Program {
public static void Main() {
Array a;
// Создание одномерного массива с нулевым 
// начальным индексом и без элементов
продолжение



428
Глава.16 .Массивы
a = new String[0];
Console.WriteLine(a.GetType()); // "System.String[]"
// Создание одномерного массива с нулевым 
// начальным индексом и без элементов
a = Array.CreateInstance(typeof(String),
new Int32[] { 0 }, new Int32[] { 0 });
Console.WriteLine(a.GetType()); // "System.String[]"
// Создание одномерного массива с начальным индексом 1 и без элементов
a = Array.CreateInstance(typeof(String),
new Int32[] { 0 }, new Int32[] { 1 });
Console.WriteLine(a.GetType()); // "System.String[*]" <-- ВНИМАНИЕ!
Console.WriteLine();
// Создание двухмерного массива с нулевым 
// начальным индексом и без элементов
a = new String[0, 0];
Console.WriteLine(a.GetType()); // "System.String[,]"
// Создание двухмерного массива с нулевым 
// начальным индексом и без элементов
a = Array.CreateInstance(typeof(String),
new Int32[] { 0, 0 }, new Int32[] { 0, 0 });
Console.WriteLine(a.GetType()); // "System.String[,]"
// Создание двухмерного массива с начальным индексом 1 и без элементов
a = Array.CreateInstance(typeof(String),
new Int32[] { 0, 0 }, new Int32[] { 1, 1 });
Console.WriteLine(a.GetType()); // "System.String[,]"
}
}
Рядом с каждой инструкцией 
Console.WriteLine
в виде комментария пока-
зан результат действия. Для одномерных массивов с нулевой нижней границей 
это 
System.String[]
, если же индексация начинается с единицы, выводится уже 
System.String[*]
. Знак 
*
свидетельствует о том, что CLR знает о ненулевой 
нижней границе. Так как в C# объявить переменную типа 
String[*]
невозможно, 
синтаксис этого языка запрещает обращение к одномерным массивам с ненулевой 
нижней границей. Впрочем, обойти это ограничение можно с помощью методов 
GetValue
и 
SetValue
класса 
Array
, но дополнительные затраты на вызов метода 
снижают эффективность работы программы.
Для многомерных массивов, независимо от нижней границы, отображается один 
и тот же тип: 
System.String[,]
. Во время выполнения CLR рассматривает их как 
массивы с ненулевой нижней границей. Логично было бы предположить, что имя 
типа будет представлено как 
System.String[*,*]
, но в CLR для многомерных 
массивов не используется знак 
*
. Ведь иначе он выводился бы во всех случаях, 
создавая путаницу.


429
Внутренняя.реализация.массивов
Доступ к элементам одномерного массива с нулевой нижней границей осу-
ществляется немного быстрее, чем доступ к элементам многомерных массивов 
или массивов с ненулевой нижней границей. Есть несколько причин такому по-
ведению. Во-первых, специальные команды для работы с одномерными массивами 
с нулевой нижней границей (
newarr

ldelem

ldelema

ldlen
и 
stelem
) позволяют 
JIT-компилятору генерировать оптимизированный код. При этом предполагает-
ся, что первый индекс равен нулю, то есть при доступе к элементам отсутствует 
необходимость вычислять смещение. Кроме того, в общем случае компилятор 
умеет выносить код проверки границ за пределы цикла. К примеру, рассмотрим 
следующий код:
using System;
public static class Program {
public static void Main() {
Int32[] a = new Int32[5];
for(Int32 index = 0; index < a.Length; index++) {
// Какие-то действия с элементом a[index]
}
}
}
Обратите внимание на вызов свойства 
Length
в проверочном выражении цикла 
for
. Фактически при этом вызывается метод, но JIT-компилятор «знает», что 
Length
является свойством класса 
Array
, поэтому создает код, в котором метод вызывается 
всего один раз, а полученный результат сохраняется в промежуточной переменной. 
Именно ее значение проверяется на каждой итерации цикла. В результате такой 
код работает очень быстро. Некоторые разработчики недооценивают возможности 
JIT-компилятора и пишут «умный код», пытаясь помочь его работе. Однако такие 
попытки практически всегда приводят к снижению производительности, а также 
делают готовую программу непонятной и неудобной для редактирования. Поэтому 
пусть свойство 
Length
вызывается автоматически.
Кроме того, JIT-компилятор «знает», что цикл обращается к элементам массива 
с нулевой нижней границей, указывая 
Length
-
1
. Поэтому он в процессе выполне-
ния генерирует код, проверяющий, все ли элементы находятся в границах массива. 
А именно, проверяется условие:
(0 >= a.GetLowerBound(0)) && ((Length – 1) <= a.GetUpperBound(0))
Проверка осуществляется до начала цикла. В случае положительного резуль-
тата компилятор не создает в теле цикла кода, проверяющего, не вышел ли индекс 
элемента за границы диапазона. Именно за счет этого обеспечивается высокая 
производительность доступа к массиву.
К сожалению, обращение к элементам многомерного массива или массива с не-
нулевой нижней границей происходит намного медленней. Ведь в этих случаях код 
проверки индекса не выносится за пределы цикла и проверка осуществляется на 
каждой итерации. Кроме того, компилятор добавляет код, вычитающий из текущего 


430
Глава.16 .Массивы
индекса нижнюю границу массива. Это также замедляет работу программы даже 
в случае многомерных массивов с нулевой нижней границей. Если вы серьезно оза-
бочены проблемой производительности, имеет смысл использовать нерегулярные 
массивы (массивы массивов).
Кроме того, в C# и CLR возможен доступ к элементам массива при помощи 
небезопасного (неверифицируемого) кода. В этом случае процедура проверки 
индексов массива просто отключается. Данная техника применима только к мас-
сивам типа 
SByte

Byte

Int16

UInt16

Int32

UInt32

Int64

UInt64

Char

Single

Double

Decimal

Boolean
, а также к массивам перечислимого типа или структуры 
значимого типа с полями одного из вышеуказанных типов.
Эту мощную возможность следует использовать крайне осторожно, так как 
она дает прямой доступ к памяти. При этом выход за границы массива не сопрово-
ждается появлением исключения; вместо этого происходит повреждение памяти, 
нарушение безопасности типов и, скорее всего, в системы безопасности программы 
появляется дефект. Поэтому сборке, содержащей небезопасный код, следует обе-
спечить полное доверие или же предоставить разрешение 
Security
Permission

включив свойство 
Skip
Verification
.
Следующий код демонстрирует три варианта доступа к двухмерному массиву, 
включая безопасный доступ, доступ через нерегулярный массив и небезопасный 
доступ:
using System;
using System.Diagnostics;
public static class Program {
private const Int32 c_numElements = 10000;
public static void Main() {
// Объявление двухмерного массива
Int32[,] a2Dim = new Int32[c_numElements, c_numElements];
// Объявление нерегулярного двухмерного массива (вектор векторов)
Int32[][] aJagged = new Int32[c_numElements][];
for (Int32 x = 0; x < c_numElements; x++)
aJagged[x] = new Int32[c_numElements];
// 1: Обращение к элементам стандартным, безопасным способом
Safe2DimArrayAccess(a2Dim);
// 2: Обращение к элементам с использованием нерегулярного массива
SafeJaggedArrayAccess(aJagged);
// 3: Обращение к элементам небезопасным методом
Unsafe2DimArrayAccess(a2Dim);
}
private static Int32 Safe2DimArrayAccess(Int32[,] a) {


431
Внутренняя.реализация.массивов
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;
}
}
Метод 
Unsafe2DimArrayAccess
имеет модификатор 
unsafe
, который необходим 
для инструкции 
fixed
языка C#. При вызове компилятора следует установить 
переключатель 
/unsafe
или флажок 
Allow.Unsafe.Code
на вкладке 
Build
окна свойств 
проекта в программе Microsoft Visual Studio.
Существуют ситуации, в которых «небезопасный» доступ оказывается опти-
мальным, но у него есть три серьезных недостатка:
‰
код обращения к элементам массива менее читабелен и более сложен в написании 
из-за присутствия инструкции 
fixed
и вычисления адресов памяти;
‰
ошибка в расчетах может привести к перезаписи памяти, не принадлежащей 
массиву, в результате возможны разрушение памяти, нарушение безопасности 
типов и потенциальные бреши в системе безопасности;
‰
из-за высокой вероятности проблем CLR запрещает работу небезопасного 
кода в средах с пониженным уровнем безопасности (таких, как Microsoft 
Silverlight).



Download 6,27 Mb.

Do'stlaringiz bilan baham:
1   ...   310   311   312   313   314   315   316   317   ...   658




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish