Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Obsolete 8 страница





· иначе, если E является перемещаемой переменной (§18.3), а выражение E.I не является инициализатором_указателя_fixed (§18.6), выдается ошибка времени компиляции;

· иначе E ссылается на фиксированную переменную, а результатом выражения является указатель на первый элемент члена I буфера фиксированного размера в E. Результат имеет тип S*, где S — тип элемента I, и классифицируется как значение.

Доступ к последующим элементам буфера фиксированного размера можно получить с помощью операций с указателем от первого элемента. В отличие от доступа к массивам, доступ к элементам буфера фиксированного размера является небезопасной операцией без проверки диапазона.

В следующем примере объявляется и используется структура с членом, являющимся буфером фиксированного размера.

unsafe struct Font
{
public int size;
public fixed char name[32];
}

class Test
{
unsafe static void PutString(string s, char* buffer, int bufSize) {
int len = s.Length;
if (len > bufSize) len = bufSize;
for (int i = 0; i < len; i++) buffer[i] = s[i];
for (int i = len; i < bufSize; i++) buffer[i] = (char)0;
}

unsafe static void Main()
{
Font f;
f.size = 10;
PutString("Times New Roman", f.name, 32);
}
}

18.7.3 Проверка определенного присваивания

Буферы фиксированного размера не подлежат проверке определенного присваивания (§5.3), а члены буфера фиксированного размера игнорируются при проверке определенного присваивания переменным типа структуры.

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

18.8 Выделение стека;

В небезопасном контексте объявление локальной переменной (§8.5.1) может включать инициализатор выделения стека, который выделяет память из стека вызова.

инициализатор_локальной_переменной:

инициализатор_stackalloc

инициализатор_stackalloc:
stackalloc неуправляемый_тип [ выражение ]

Неуправляемый_тип указывает тип элементов, которые будут сохраняться во вновь выделенном месте, а выражение указывает количество этих элементов. Совместно они указывают необходимый размер выделения. Так как размер выделения стека не может быть отрицательным, выдается ошибка времени компиляции, если число элементов задано константным_выражением, дающим в результате отрицательное значение.

Для инициализатора выделения стека вида stackalloc T[E] требуется, чтобы T было неуправляемого типа (§18.2), а E было выражением типа int. Эта конструкция выделяет E * sizeof(T) байт из стека вызова и возвращает указатель (типа T*) на вновь выделенный блок. Если E — отрицательное значение, то поведение неопределенное. Если E равно нулю, то выделение не производится, а возвращаемый указатель определяется реализацией. Если не хватает памяти для выделения блока заданного размера, выдается System.StackOverflowException.

Содержимое вновь выделенной памяти неопределенное.

Инициализаторы выделения стека не допускаются в блоках catch или finally (§8.10).

Не существует способ явного освобождения памяти, выделенной с помощью stackalloc. Все блоки выделенной стеку памяти, созданные во время выполнения члена функции, автоматически удаляются при возврате из члена функции. Это соответствует функции alloca, расширение, обычно встречающееся в реализациях C и C++.

В примере

using System;

class Test
{
static string IntToString(int value) {
int n = value >= 0? value: -value;
unsafe {
char* buffer = stackalloc char[16];
char* p = buffer + 16;
do {
*--p = (char)(n % 10 + '0');
n /= 10;
} while (n!= 0);
if (value < 0) *--p = '-';
return new string(p, 0, (int)(buffer + 16 - p));
}
}

static void Main() {
Console.WriteLine(IntToString(12345));
Console.WriteLine(IntToString(-999));
}
}

инициализатор stackalloc используется в методе IntToString для выделения буфера размером 16 символов в стеке. Этот буфер автоматически удаляется при возврате метода.

18.9 Динамическое выделение памяти

Кроме оператора stackalloc, C# не предоставляет предопределенные конструкции для управления памятью, не собираемой сборщиком мусора. Такие службы обычно предоставляются поддержкой библиотек классов или импортируются непосредственно из операционной системы. В следующем примере показано в классе Memory, как можно обратиться к функциям кучи операционной системы из C#:

using System;
using System.Runtime.InteropServices;

public unsafe class Memory
{
// Дескриптор для кучи процесса. Этот дескриптор используется во всех вызовах
// API HeapXXX в методах внизу.

static int ph = GetProcessHeap();

// Конструктор экземпляра Private для предотвращения создания экземпляра.

private Memory() {}

// Выделяет блок памяти заданного размера. Выделенная память
// автоматически инициализируется нулями.

public static void* Alloc(int size) {
void* result = HeapAlloc(ph, HEAP_ZERO_MEMORY, size);
if (result == null) throw new OutOfMemoryException();
return result;
}

// Копирует счетчик байт из src в dst. Блоки исходный и конечный
// могут перекрываться.

public static void Copy(void* src, void* dst, int count) {
byte* ps = (byte*)src;
byte* pd = (byte*)dst;
if (ps > pd) {
for (; count!= 0; count--) *pd++ = *ps++;
}
else if (ps < pd) {
for (ps += count, pd += count; count!= 0; count--) *--pd = *--ps;
}
}

// Освобождает блок памяти.

public static void Free(void* block) {
if (!HeapFree(ph, 0, block)) throw new InvalidOperationException();
}

// Перераспределяет блок памяти. Если запрос перераспределения на
// больший размер, дополнительная область памяти автоматически
// инициализируется нулями.

public static void* ReAlloc(void* block, int size) {
void* result = HeapReAlloc(ph, HEAP_ZERO_MEMORY, block, size);
if (result == null) throw new OutOfMemoryException();
return result;
}

// Возвращает размер блока памяти.

public static int SizeOf(void* block) {
int result = HeapSize(ph, 0, block);
if (result == -1) throw new InvalidOperationException();
return result;
}

// Флаги API кучи

const int HEAP_ZERO_MEMORY = 0x00000008;

// Функции API кучи

[DllImport("kernel32")]
static extern int GetProcessHeap();

[DllImport("kernel32")]
static extern void* HeapAlloc(int hHeap, int flags, int size);

[DllImport("kernel32")]
static extern bool HeapFree(int hHeap, int flags, void* block);

[DllImport("kernel32")]
static extern void* HeapReAlloc(int hHeap, int flags,
void* block, int size);

[DllImport("kernel32")]
static extern int HeapSize(int hHeap, int flags, void* block);
}

Пример использования класса Memory:

class Test
{
static void Main() {
unsafe {
byte* buffer = (byte*)Memory.Alloc(256);
try {
for (int i = 0; i < 256; i++) buffer[i] = (byte)i;
byte[] array = new byte[256];
fixed (byte* p = array) Memory.Copy(buffer, p, 256);
}
finally {
Memory.Free(buffer);
}
for (int i = 0; i < 256; i++) Console.WriteLine(array[i]);
}
}
}

В этом примере выделяется 256 байт памяти через Memory.Alloc и блок памяти инициализируется значениями, возрастающими от 0 до 255. Затем размещается байтовый массив из 256 элементов и используется Memory.Copy для копирования содержимого блока памяти в байтовый массив. Наконец, этот блок памяти освобождается с помощью Memory.Free и содержимое байтового массива выводится на консоль.







Дата добавления: 2015-09-07; просмотров: 419. Нарушение авторских прав; Мы поможем в написании вашей работы!




Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...


Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...


Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...


Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

Метод Фольгарда (роданометрия или тиоцианатометрия) Метод Фольгарда основан на применении в качестве осадителя титрованного раствора, содержащего роданид-ионы SCN...

Потенциометрия. Потенциометрическое определение рН растворов Потенциометрия - это электрохимический метод иссле­дования и анализа веществ, основанный на зависимости равновесного электродного потенциала Е от активности (концентрации) определяемого вещества в исследуемом рас­творе...

Гальванического элемента При контакте двух любых фаз на границе их раздела возникает двойной электрический слой (ДЭС), состоящий из равных по величине, но противоположных по знаку электрических зарядов...

ФАКТОРЫ, ВЛИЯЮЩИЕ НА ИЗНОС ДЕТАЛЕЙ, И МЕТОДЫ СНИЖЕНИИ СКОРОСТИ ИЗНАШИВАНИЯ Кроме названных причин разрушений и износов, знание которых можно использовать в системе технического обслуживания и ремонта машин для повышения их долговечности, немаловажное значение имеют знания о причинах разрушения деталей в результате старения...

Различие эмпиризма и рационализма Родоначальником эмпиризма стал английский философ Ф. Бэкон. Основной тезис эмпиризма гласит: в разуме нет ничего такого...

Индекс гингивита (PMA) (Schour, Massler, 1948) Для оценки тяжести гингивита (а в последующем и ре­гистрации динамики процесса) используют папиллярно-маргинально-альвеолярный индекс (РМА)...

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия